Annotation of embedaddon/php/Zend/ZEND_CHANGES, revision 1.1
1.1 ! misho 1: Changes in the Zend Engine 2.0
! 2:
! 3: * New Object Model.
! 4:
! 5: The Zend Engine's handling of objects has been completely
! 6: changed in order to allow for new features, but also to increase
! 7: its performance.
! 8:
! 9: Objects were handled in previous versions like primitive types
! 10: (for instance integers and strings). The drawback of this method
! 11: is, that semantically the whole object was copied when a
! 12: variable was assigned or parameters were passed to a method. The
! 13: new approach refers to objects by handle and not by value (one
! 14: can think of a handle as an object's ID).
! 15:
! 16: Many PHP programmers aren't even aware of the copying quirks of
! 17: the old object model and, therefore, there is a relatively good
! 18: chance that the amount of PHP applications that will work out of
! 19: the box or after a very small amount of modifications would be
! 20: high.
! 21:
! 22: * $this
! 23:
! 24: Unlike in Zend Engine 1 the pseudo variable $this cannot be
! 25: exchanged in Zend Engine 2. You can of course modify or work with
! 26: an object by using $this but you cannot replace $this with another
! 27: object to change the original object.
! 28:
! 29: Example:
! 30:
! 31: <?php
! 32: class Foo {
! 33: function replace($other)
! 34: {
! 35: $this = $other;
! 36: }
! 37: }
! 38:
! 39: $object = new Foo;
! 40: $object->prop = 'Hello';
! 41:
! 42: $other = new Foo;
! 43: $other->prop = 'Bye';
! 44:
! 45: $object->replace($other);
! 46:
! 47: print $object->prop; // still shows 'Hello'
! 48:
! 49: ?>
! 50:
! 51: Zend Engine 2.0 will issue a compile error, if an assignment
! 52: to $this is found.
! 53:
! 54: * Private and Protected Members.
! 55:
! 56: The Zend Engine 2.0 introduces private and protected member
! 57: variables. Note that for performance reasons no error message is
! 58: emitted in case of an illegal access to a private or protectecd
! 59: member variable.
! 60:
! 61: Example:
! 62:
! 63: <?php
! 64: class MyClass {
! 65: private $Hello = "Hello, World!\n";
! 66: protected $Bar = "Hello, Foo!\n";
! 67: protected $Foo = "Hello, Bar!\n";
! 68:
! 69: function printHello() {
! 70: print "MyClass::printHello() " . $this->Hello;
! 71: print "MyClass::printHello() " . $this->Bar;
! 72: print "MyClass::printHello() " . $this->Foo;
! 73: }
! 74: }
! 75:
! 76: class MyClass2 extends MyClass {
! 77: protected $Foo;
! 78:
! 79: function printHello() {
! 80: MyClass::printHello(); /* Should print */
! 81: print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */
! 82: print "MyClass2::printHello() " . $this->Bar; /* Shouldn't print (not declared)*/
! 83: print "MyClass2::printHello() " . $this->Foo; /* Should print */
! 84: }
! 85: }
! 86:
! 87: $obj = new MyClass();
! 88: print $obj->Hello; /* Shouldn't print out anything */
! 89: print $obj->Bar; /* Shouldn't print out anything */
! 90: print $obj->Foo; /* Shouldn't print out anything */
! 91: $obj->printHello(); /* Should print */
! 92:
! 93: $obj = new MyClass2();
! 94: print $obj->Hello; /* Shouldn't print out anything */
! 95: print $obj->Bar; /* Shouldn't print out anything */
! 96: print $obj->Foo; /* Shouldn't print out anything */
! 97: $obj->printHello();
! 98: ?>
! 99:
! 100: Protected member variables can be accessed in classes extending the
! 101: class they are declared in, whereas private member variables can
! 102: only be accessed by the class they belong to.
! 103:
! 104: * Private and protected methods.
! 105:
! 106: The Zend Engine 2.0 introduces private and protected methods.
! 107:
! 108: Example:
! 109:
! 110: <?php
! 111: class Foo {
! 112: private function aPrivateMethod() {
! 113: echo "Foo::aPrivateMethod() called.\n";
! 114: }
! 115:
! 116: protected function aProtectedMethod() {
! 117: echo "Foo::aProtectedMethod() called.\n";
! 118: $this->aPrivateMethod();
! 119: }
! 120: }
! 121:
! 122: class Bar extends Foo {
! 123: public function aPublicMethod() {
! 124: echo "Bar::aPublicMethod() called.\n";
! 125: $this->aProtectedMethod();
! 126: }
! 127: }
! 128:
! 129: $o = new Bar;
! 130: $o->aPublicMethod();
! 131: ?>
! 132:
! 133: Old code that has no user-defined classes or functions named
! 134: 'public', 'protected' or 'private' should run without modifications.
! 135:
! 136: * Abstract Classes and Methods.
! 137:
! 138: The Zend Engine 2.0 introduces abstract classes and methods. An
! 139: abstract method only declares the method's signature and does not
! 140: provide an implementation. A class that contains abstract methods
! 141: needs to be declared abstract.
! 142:
! 143: Example:
! 144:
! 145: <?php
! 146: abstract class AbstractClass {
! 147: abstract public function test();
! 148: }
! 149:
! 150: class ImplementedClass extends AbstractClass {
! 151: public function test() {
! 152: echo "ImplementedClass::test() called.\n";
! 153: }
! 154: }
! 155:
! 156: $o = new ImplementedClass;
! 157: $o->test();
! 158: ?>
! 159:
! 160: Classes that do not have abstract methods can be declared abstract
! 161: to prevent them from being instantiated.
! 162:
! 163: Old code that has no user-defined classes or functions named
! 164: 'abstract' should run without modifications.
! 165:
! 166: * Interfaces.
! 167:
! 168: The Zend Engine 2.0 introduces interfaces. A class may implement
! 169: an arbitrary list of interfaces.
! 170:
! 171: Example:
! 172:
! 173: <?php
! 174: interface Printable {
! 175: public function dump();
! 176: }
! 177:
! 178: class PrintableExample implements Printable {
! 179: public function dump() {
! 180: // ...
! 181: }
! 182: }
! 183: ?>
! 184:
! 185: Old code that has no user-defined classes or functions named
! 186: 'interface' or 'implements' should run without modifications.
! 187:
! 188: An interface may extend one or more base interfaces (but not
! 189: implement them). Neither a class nor an interface can inherit
! 190: methods of the same name from different root interfaces.
! 191:
! 192: Interfaces may contain abstract static methods.
! 193:
! 194: Example:
! 195:
! 196: <?php
! 197: interface Printable {
! 198: function dump();
! 199: }
! 200:
! 201: interface Streamable extends Printable {
! 202: function writeToStream();
! 203: static function readFromStream();
! 204: }
! 205:
! 206: class PrintableExample implements Streamable {
! 207: public function dump() {
! 208: // ...
! 209: }
! 210: function writeToStream() {
! 211: // ...
! 212: }
! 213: static function readFromStream() {
! 214: // ...
! 215: }
! 216: }
! 217: ?>
! 218:
! 219: A class that does not implement all interface methods must be
! 220: declared as an abstract class.
! 221:
! 222: * Class Type Hints.
! 223:
! 224: While remaining loosely typed the Zend Engine 2.0 introduces the
! 225: ability to use class type hints to declare the expected class of
! 226: objects that are passed as parameters to a method.
! 227:
! 228: Example:
! 229:
! 230: <?php
! 231: interface Foo {
! 232: function a(Foo $foo);
! 233: }
! 234:
! 235: interface Bar {
! 236: function b(Bar $bar);
! 237: }
! 238:
! 239: class FooBar implements Foo, Bar {
! 240: function a(Foo $foo) {
! 241: // ...
! 242: }
! 243:
! 244: function b(Bar $bar) {
! 245: // ...
! 246: }
! 247: }
! 248:
! 249: $a = new FooBar;
! 250: $b = new FooBar;
! 251:
! 252: $a->a($b);
! 253: $a->b($b);
! 254: ?>
! 255:
! 256: These class type hints are not checked upon compilation, as would
! 257: be the case in a typed language, but during runtime.
! 258:
! 259: This means that
! 260:
! 261: function foo(ClassName $object) {
! 262: // ...
! 263: }
! 264:
! 265: is equivalent to
! 266:
! 267: function foo($object) {
! 268: if (!($object instanceof ClassName)) {
! 269: die('Argument 1 must be an instance of ClassName');
! 270: }
! 271: }
! 272:
! 273: This syntax only applies to objects/classes, not built-in types.
! 274:
! 275: * Final methods and classes.
! 276:
! 277: The Zend Engine 2.0 introduces the "final" keyword to declare
! 278: final methods. Those cannot be overridden by sub-classes.
! 279:
! 280: Example:
! 281:
! 282: <?php
! 283: class Foo {
! 284: final function bar() {
! 285: // ...
! 286: }
! 287: }
! 288: ?>
! 289:
! 290: It is furthermore possible to make a class final. Doing this
! 291: prevents a class from being specialized (it cannot be inherited
! 292: by another class). There's no need to declare the methods of
! 293: a final class themselves as final.
! 294:
! 295: Example:
! 296:
! 297: <?php
! 298: final class Foo {
! 299: // class definition
! 300: }
! 301: // the next line is impossible
! 302: // class Bork extends Foo {}
! 303: ?>
! 304:
! 305: Properties cannot be final. See per-class constants below.
! 306:
! 307: Old code that has no user-defined classes or functions named
! 308: 'final' should run without modifications.
! 309:
! 310: * Object Cloning.
! 311:
! 312: The Zend Engine 1.0 offered no way a user could decide what copy
! 313: constructor to run when an object is duplicated. During
! 314: duplication, the Zend Engine 1.0 did a bitwise copy making an
! 315: identical replica of all the object's properties.
! 316:
! 317: Creating a copy of an object with fully replicated properties is
! 318: not always the wanted behavior. A good example of the need for
! 319: copy constructors, is if you have an object which represents a
! 320: GTK window and the object holds the resource of this GTK window,
! 321: when you create a duplicate you might want to create a new
! 322: window with the same properties and have the new object hold the
! 323: resource of the new window. Another example is if your object
! 324: holds a reference to another object which it uses and when you
! 325: replicate the parent object you want to create a new instance of
! 326: this other object so that the replica has its own separate copy.
! 327:
! 328: An object copy is created by using the clone operator.
! 329:
! 330: Example:
! 331:
! 332: <?php
! 333: $copy_of_object = clone $object;
! 334: ?>
! 335:
! 336: When the developer asks to create a new copy of an object, the
! 337: Zend Engine will check if a __clone() method has been defined or
! 338: not. If not, it will call a default __clone() which will copy
! 339: all of the object's properties. If a __clone() method is
! 340: defined, then it will be responsible to set the necessary
! 341: properties in the created object. For convenience, the engine
! 342: ensures, that the clone will be initialized with all of the
! 343: properties from the source object, so that developers can start
! 344: with a by-value replica of the source object, and only override
! 345: properties that need to be changed.
! 346:
! 347: Example:
! 348: <?php
! 349: class MyCloneable {
! 350: static $id = 0;
! 351:
! 352: function MyCloneable() {
! 353: $this->id = self::$id++;
! 354: }
! 355:
! 356: function __clone() {
! 357: $this->address = 'New York';
! 358: $this->id = self::$id++;
! 359: }
! 360: }
! 361:
! 362: $obj = new MyCloneable();
! 363:
! 364: $obj->name = 'Hello';
! 365: $obj->address = 'Tel-Aviv';
! 366:
! 367: $obj_clone = clone $obj;
! 368:
! 369: print $obj->id . "\n";
! 370: print $obj->name . "\n";
! 371: print $obj->address . "\n";
! 372:
! 373: print $obj_clone->id . "\n";
! 374: print $obj_clone->name . "\n";
! 375: print $obj_clone->address . "\n";
! 376: ?>
! 377:
! 378: * Unified Constructors.
! 379:
! 380: The Zend Engine allows developers to declare constructor methods
! 381: for classes. Classes which have a constructor method call this
! 382: method on each newly-created object, so it is suitable for any
! 383: initialization that the object may need before it can be used.
! 384:
! 385: With the Zend Engine 1.0, constructor methods were class methods
! 386: that had the same name as the class itself. Since it is very
! 387: common to call parent constructors from derived classes, the way
! 388: the Zend Engine 1.0 worked made it a bit cumbersome to move
! 389: classes around in a large class hierarchy. If a class is moved
! 390: to reside under a different parent, the constructor name of that
! 391: parent changes as well, and the code in the derived class that
! 392: calls the parent constructor has to be modified.
! 393:
! 394: The Zend Engine 2.0 introduces a standard way of declaring
! 395: constructor methods by calling them by the name __construct().
! 396:
! 397: Example:
! 398:
! 399: <?php
! 400: class BaseClass {
! 401: function __construct() {
! 402: print "In BaseClass constructor\n";
! 403: }
! 404: }
! 405:
! 406: class SubClass extends BaseClass {
! 407: function __construct() {
! 408: parent::__construct();
! 409: print "In SubClass constructor\n";
! 410: }
! 411: }
! 412:
! 413: $obj = new BaseClass();
! 414: $obj = new SubClass();
! 415: ?>
! 416:
! 417: For backwards compatibility, if the Zend Engine 2.0 cannot find
! 418: a __construct() function for a given class, it will search for
! 419: the old-style constructor function, by the name of the class.
! 420: Effectively, it means that the only case that would have
! 421: compatibility issues is if the class had a method named
! 422: __construct() which was used for different semantics.
! 423:
! 424: * Destructors.
! 425:
! 426: Having the ability to define destructors for objects can be very
! 427: useful. Destructors can log messages for debugging, close
! 428: database connections and do other clean-up work.
! 429:
! 430: No mechanism for object destructors existed in the Zend Engine
! 431: 1.0, although PHP had already support for registering functions
! 432: which should be run on request shutdown.
! 433:
! 434: The Zend Engine 2.0 introduces a destructor concept similar to
! 435: that of other object-oriented languages, such as Java: When the
! 436: last reference to an object is destroyed the object's
! 437: destructor, which is a class method name __destruct() that
! 438: recieves no parameters, is called before the object is freed
! 439: from memory.
! 440:
! 441: Example:
! 442:
! 443: <?php
! 444: class MyDestructableClass {
! 445: function __construct() {
! 446: print "In constructor\n";
! 447: $this->name = 'MyDestructableClass';
! 448: }
! 449:
! 450: function __destruct() {
! 451: print 'Destroying ' . $this->name . "\n";
! 452: }
! 453: }
! 454:
! 455: $obj = new MyDestructableClass();
! 456: ?>
! 457:
! 458: Like constructors, parent destructors will not be called
! 459: implicitly by the engine. In order to run a parent destructor,
! 460: one would have to explicitly call parent::__destruct() in the
! 461: destructor body.
! 462:
! 463: * Constants.
! 464:
! 465: The Zend Engine 2.0 introduces per-class constants.
! 466:
! 467: Example:
! 468:
! 469: <?php
! 470: class Foo {
! 471: const constant = 'constant';
! 472: }
! 473:
! 474: echo 'Foo::constant = ' . Foo::constant . "\n";
! 475: ?>
! 476:
! 477: Old code that has no user-defined classes or functions
! 478: named 'const' will run without modifications.
! 479:
! 480: * Exceptions.
! 481:
! 482: The Zend Engine 1.0 had no exception handling. The Zend Engine 2.0
! 483: introduces a exception model similar to that of other programming
! 484: languages. But there is no catch all and no finally clause.
! 485:
! 486: Old code that has no user-defined classes or functions 'catch',
! 487: 'throw' and 'try' will run without modifications.
! 488:
! 489: Exceptions can be rethrown in catch blocks. Also it is possible to
! 490: have multiple catch blocks. In that case the caught exception is
! 491: compared with the classtype of each catch block from top to bottom
! 492: and the first block that has a 'instanceof' match gets executed.
! 493: When the catch block finishes execution continues at the end of
! 494: the last catch block. If no catch block has a 'instanceof' match
! 495: then the next try/catch block is searched until no more try/catch
! 496: blocks are available. In that case the exception is an uncaught
! 497: exception and the program terminates with showing the exception.
! 498:
! 499: Example:
! 500:
! 501: <?php
! 502: class MyException {
! 503: function __construct($exception) {
! 504: $this->exception = $exception;
! 505: }
! 506:
! 507: function Display() {
! 508: print "MyException: $this->exception\n";
! 509: }
! 510: }
! 511:
! 512: class MyExceptionFoo extends MyException {
! 513: function __construct($exception) {
! 514: $this->exception = $exception;
! 515: }
! 516:
! 517: function Display() {
! 518: print "MyException: $this->exception\n";
! 519: }
! 520: }
! 521:
! 522: try {
! 523: throw new MyExceptionFoo('Hello');
! 524: }
! 525: catch (MyException $exception) {
! 526: $exception->Display();
! 527: }
! 528: catch (Exception $exception) {
! 529: echo $exception;
! 530: }
! 531: ?>
! 532:
! 533: Even though the above example shows that it is possible to define
! 534: exception classes that don't inherit from Exception it is best to
! 535: do so. This is because the internal Exception class can gather a
! 536: lot of information otherwise not available. The PHP code emulation
! 537: code would look something like shown below. The comments show the
! 538: meaning of each property. As the code shows it is possible to read
! 539: any available information by using the getter methods. But since
! 540: some of the methods are used internally they are marked final. All
! 541: in all the class is very restrictive because it must be ensured
! 542: that anything used internally always works as expected.
! 543:
! 544: Emulating class Exception:
! 545:
! 546: <?php
! 547: class Exception {
! 548: function __construct(/*string*/ $message=NULL, /*int*/ $code=0) {
! 549: if (func_num_args()) {
! 550: $this->message = $message;
! 551: }
! 552: $this->code = $code;
! 553: $this->file = __FILE__; // of throw clause
! 554: $this->line = __LINE__; // of throw clause
! 555: $this->trace = debug_backtrace();
! 556: $this->string = StringFormat($this);
! 557: }
! 558:
! 559: protected $message = 'Unknown exception'; // exception message
! 560: protected $code = 0; // user defined exception code
! 561: protected $file; // source filename of exception
! 562: protected $line; // source line of exception
! 563:
! 564: private $trace; // backtrace of exception
! 565: private $string; // internal only!!
! 566:
! 567: final function getMessage() {
! 568: return $this->message;
! 569: }
! 570: final function getCode() {
! 571: return $this->code;
! 572: }
! 573: final function getFile() {
! 574: return $this->file;
! 575: }
! 576: final function getTrace() {
! 577: return $this->trace;
! 578: }
! 579: final function getTraceAsString() {
! 580: return self::TraceFormat($this);
! 581: }
! 582: function _toString() {
! 583: return $this->string;
! 584: }
! 585: static private function StringFormat(Exception $exception) {
! 586: // ... a function not available in PHP scripts
! 587: // that returns all relevant information as a string
! 588: }
! 589: static private function TraceFormat(Exception $exception) {
! 590: // ... a function not available in PHP scripts
! 591: // that returns the backtrace as a string
! 592: }
! 593: }
! 594: ?>
! 595:
! 596: If you derive your exception classes from this Exception base class
! 597: your exceptions will be nicely shown in the builtin handler for
! 598: uncaught exceptions.
! 599:
! 600: Note: The method getMessage() is a final read only access method to
! 601: the private proeprty message that is set in the constructor. If you
! 602: feel a need to overwrite the exception display then overload method
! 603: __toString() in your derived class or implement your own extneral
! 604: exception display function to accomplish your desired formatting.
! 605:
! 606: Example:
! 607:
! 608: <?php
! 609: function display_exception(Exception $ex)
! 610: {
! 611: echo 'Exception: ' . $ex->getMessage() . 'with backtrace: <pre>';
! 612: echo $ex->getTrace();
! 613: echo '</pre>';
! 614: }
! 615:
! 616: try
! 617: {
! 618: // your code here
! 619: }
! 620: catch (Exception $ex)
! 621: {
! 622: display_exeption($ex);
! 623: }
! 624: ?>
! 625:
! 626: * Dereferencing objects returned from functions.
! 627:
! 628: Example:
! 629:
! 630: <?php
! 631: class Circle {
! 632: function draw() {
! 633: print "Circle\n";
! 634: }
! 635: }
! 636:
! 637: class Square {
! 638: function draw() {
! 639: print "Square\n";
! 640: }
! 641: }
! 642:
! 643: function ShapeFactoryMethod($shape) {
! 644: switch ($shape) {
! 645: case 'Circle': return new Circle();
! 646: case 'Square': return new Square();
! 647: }
! 648: }
! 649:
! 650: ShapeFactoryMethod('Circle')->draw();
! 651: ShapeFactoryMethod('Square')->draw();
! 652: ?>
! 653:
! 654: * Member variables of classes can now be initialized.
! 655:
! 656: Example:
! 657:
! 658: <?php
! 659: class foo {
! 660: static $my_static = 5;
! 661: public $my_prop = 'bla';
! 662: }
! 663:
! 664: print foo::$my_static;
! 665:
! 666: $obj = foo;
! 667:
! 668: print $obj->my_prop;
! 669: ?>
! 670:
! 671: * Static Methods.
! 672:
! 673: The Zend Engine 2.0 introduces the 'static' keyword to declare
! 674: a method static, thus callable from outside the object context.
! 675:
! 676: Example:
! 677:
! 678: <?php
! 679: class Foo {
! 680: public static function aStaticMethod() {
! 681: // ...
! 682: }
! 683: }
! 684:
! 685: Foo::aStaticMethod();
! 686: ?>
! 687:
! 688: The pseudo variable $this is not available inside a method that
! 689: has been declared static.
! 690:
! 691: * instanceof.
! 692: New support for an instanceof operator which checks if an object
! 693: is of a certain class or interface type.
! 694:
! 695: Example:
! 696:
! 697: <?php
! 698:
! 699: class Foo {
! 700: }
! 701:
! 702: $obj = new Foo();
! 703: if ($obj instanceof Foo) {
! 704: print "Yay!\n";
! 705: }
! 706: ?>
! 707:
! 708: * Parameters that are passed by reference to a function
! 709: may now have default values.
! 710:
! 711: Example:
! 712:
! 713: <?php
! 714: function my_function(&$var = null) {
! 715: if ($var === null) {
! 716: die('$var needs to have a value');
! 717: }
! 718: }
! 719: ?>
! 720:
! 721: * __autoload().
! 722:
! 723: The __autoload() interceptor function will be automatically called
! 724: when an undeclared class is to be instantiated. The name of that
! 725: class will be passed to the __autoload() interceptor function as its
! 726: only argument. __autoload() must succeed in loading the class. If it
! 727: doesn't then an E_ERROR is emitted.
! 728:
! 729: Example:
! 730:
! 731: <?php
! 732: function __autoload($className) {
! 733: include_once $className . '.php';
! 734: }
! 735:
! 736: $object = new ClassName;
! 737: ?>
! 738:
! 739: * Method calls and property accesses can be overloaded
! 740: by class methods __call(), __get() and __set().
! 741:
! 742: __get() and __set() Example:
! 743:
! 744: <?php
! 745: class Setter {
! 746: public $n;
! 747: public $x = array('a' => 1, 'b' => 2, 'c' => 3);
! 748:
! 749: function __get($nm) {
! 750: print "Getting [$nm]\n";
! 751:
! 752: if(isset($this->x[$nm])) {
! 753: $r = $this->x[$nm];
! 754: print "Returning: $r\n";
! 755: return $r;
! 756: } else {
! 757: print "Nothing!\n";
! 758: }
! 759: }
! 760:
! 761: function __set($nm, $val) {
! 762: print "Setting [$nm] to $val\n";
! 763:
! 764: if(isset($this->x[$nm])) {
! 765: $this->x[$nm] = $val;
! 766: print "OK!\n";
! 767: } else {
! 768: print "Not OK!\n";
! 769: }
! 770: }
! 771: }
! 772:
! 773: $foo = new Setter();
! 774: $foo->n = 1;
! 775: $foo->a = 100;
! 776: $foo->a++;
! 777: $foo->z++;
! 778: var_dump($foo);
! 779: ?>
! 780:
! 781: __call() Example:
! 782:
! 783: <?php
! 784: class Caller {
! 785: var $x = array(1, 2, 3);
! 786:
! 787: function __call($m, $a) {
! 788: print "Method $m called:\n";
! 789: var_dump($a);
! 790: return $this->x;
! 791: }
! 792: }
! 793:
! 794: $foo = new Caller();
! 795: $a = $foo->test(1, '2', 3.4, true);
! 796: var_dump($a);
! 797: ?>
! 798:
! 799: * Iteration
! 800:
! 801: Objects may be iterated in an overloaded way when used with
! 802: foreach. The default behavior is to iterate over all properties
! 803: with respect to property visibility.
! 804:
! 805: Example:
! 806:
! 807: <?php
! 808: class Foo {
! 809: var $x = 1;
! 810: var $y = 2;
! 811: }
! 812:
! 813: $obj = new Foo;
! 814:
! 815: foreach ($obj as $prp_name => $prop_value) {
! 816: // using the property
! 817: }
! 818: ?>
! 819:
! 820: Each class whose instances can be iterated with foreach should
! 821: implement the empty interface 'Traversable'. Hence any object
! 822: that says it implements 'Traversable' can be used with foreach.
! 823:
! 824: The interfaces 'IteratorAggregate' and 'Iterator' allow to specify
! 825: how class objects are iterated in PHP code. The first of them simply
! 826: has a method 'getIterator' which must return an object that either
! 827: implements the interface 'Iterator' or is instantiated from an
! 828: internal class that can be iterated.
! 829:
! 830: Example:
! 831:
! 832: <?php
! 833: class ObjectIterator implements Iterator {
! 834:
! 835: private $obj;
! 836: private $num;
! 837:
! 838: function __construct($obj) {
! 839: $this->obj = $obj;
! 840: }
! 841: function rewind() {
! 842: $this->num = 0;
! 843: }
! 844: function valid() {
! 845: return $this->num < $this->obj->max;
! 846: }
! 847: function key() {
! 848: return $this->num;
! 849: }
! 850: function current() {
! 851: switch($this->num) {
! 852: case 0: return "1st";
! 853: case 1: return "2nd";
! 854: case 2: return "3rd";
! 855: default: return $this->num."th";
! 856: }
! 857: }
! 858: function next() {
! 859: $this->num++;
! 860: }
! 861: }
! 862:
! 863: class Object implements IteratorAggregate {
! 864:
! 865: public $max = 3;
! 866:
! 867: function getIterator() {
! 868: return new ObjectIterator($this);
! 869: }
! 870: }
! 871:
! 872: $obj = new Object;
! 873:
! 874: // this foreach ...
! 875: foreach($obj as $key => $val) {
! 876: echo "$key = $val\n";
! 877: }
! 878:
! 879: // matches the following 7 lines with the for directive.
! 880: $it = $obj->getIterator();
! 881: for($it->rewind(); $it->valid(); $it->next()) {
! 882: $key = $it->key();
! 883: $val = $it->current();
! 884: echo "$key = $val\n";
! 885: }
! 886: unset($it);
! 887: ?>
! 888:
! 889: The matching for directive is very intersting here since it shows
! 890: the use of all abstract methods declared in the interfaces Iterator
! 891: and IteratorAggregate respectively.
! 892:
! 893: * Array overloading
! 894:
! 895: Objects can be used with Array notation when they implement the
! 896: interface ArrayAccess. You cannot use such objects in standard
! 897: array functions, however you have full control over the array
! 898: notation. This allows lazy initialization or read only array.
! 899:
! 900: Note that setting [] results in a call to offsetSet() with
! 901: index being NULL. That means that as with standard arrays you
! 902: cannot store NULL keys.
! 903:
! 904: Example:
! 905:
! 906: <?php
! 907: class ArrayClass implements ArrayAccess {
! 908: public $a = array();
! 909:
! 910: function offsetExists($index) {
! 911: return array_key_exists($index, $this->a);
! 912: }
! 913: function offsetGet($index) {
! 914: return $this->a[$index];
! 915: }
! 916: function offsetSet($index, $newval) {
! 917: return $this->a[$index] = $newval;
! 918: }
! 919: function offsetUnset($index) {
! 920: unset($this->a[$index]);
! 921: }
! 922: }
! 923:
! 924: $obj = new ArrayClass;
! 925:
! 926: $obj[0] = 'bla'; // calls offsetSet(0,'bla')
! 927: $obj[] = 42; // calls offsetSet(NULL, 42)
! 928: $x = $obj[0]; // calls offsetGet(0)
! 929: $b = isset($obj[0]); // calls offsetExists(0)
! 930: unset($obj[0]); // calls offsetUnset(0)
! 931: ?>
! 932:
! 933:
! 934: * __METHOD__
! 935:
! 936: The pseudo constant __METHOD__ shows the current class and method
! 937: when used inside a method and the function when used outside of a
! 938: class.
! 939:
! 940: Example:
! 941:
! 942: <?php
! 943: class Foo {
! 944: function Show() {
! 945: echo __FILE__ . '(' . __LINE__ . ')' . __METHOD__;
! 946: }
! 947: }
! 948: function Test() {
! 949: echo __FILE__ . '(' . __LINE__ . ')' . __METHOD__;
! 950: }
! 951: ?>
! 952:
! 953: * __toString()
! 954:
! 955: The magic method __toString() allows to overload the object to
! 956: string conversion. This conversion is only done automatically for
! 957: the printing functions (echo, print) but not for other functions
! 958: that expect strings. Also the function __toString is not used in
! 959: places where objects are not allowed but strings are like array
! 960: indices. Note that specialized objects may be converted to a string
! 961: in any place but without calling __toString().
! 962:
! 963: Example:
! 964:
! 965: <?php
! 966: class Foo {
! 967: function __toString() {
! 968: return "What ever";
! 969: }
! 970: }
! 971:
! 972: $obj = new Foo;
! 973:
! 974: $str = (string) $obj; // call __toString()
! 975:
! 976: echo $obj; // call __toString()
! 977:
! 978: $ar = array();
! 979: $ar[(string)$obj]; // this works
! 980: $ar[$obj]; // this is not allowed
! 981: ?>
! 982:
! 983: * Reflection API
! 984:
! 985: PHP 5 comes with a complete Reflection API that adds the ability to
! 986: reverse-engineer classes, interfaces, functions and methods as well
! 987: as extensions.
! 988:
! 989: The Reflection API also offers ways of getting doc comments for
! 990: functions, classes and methods.
! 991:
! 992: Nearly all aspects of object oriented code can be reflected by
! 993: using the Reflection API which is documented separately:
! 994: http://sitten-polizei.de/php/reflection_api/docs/language.reflection.html
! 995:
! 996: Example:
! 997:
! 998: <?php
! 999: class Foo {
! 1000: public $prop;
! 1001: function Func($name) {
! 1002: echo "Hello $name";
! 1003: }
! 1004: }
! 1005:
! 1006: ReflectionClass::export('Foo');
! 1007: ReflectionObject::export(new Foo);
! 1008: ReflectionMethod::export('Foo', 'func');
! 1009: ReflectionProperty::export('Foo', 'prop');
! 1010: ReflectionExtension::export('standard');
! 1011: ?>
! 1012:
! 1013: * New memory manager
! 1014: The Zend Engine has a new memory manager which allows it to run efficiently
! 1015: in multi-threaded environments as it doesn't need to use mutexes to lock
! 1016: and unlock during allocation/deallocation.
! 1017:
! 1018: * Others
! 1019: Probably other changes which we forgot to list. This list will be kept up-to-date
! 1020: as much as possible.
! 1021:
! 1022:
! 1023: Changes in the Zend Engine 1.0
! 1024:
! 1025: The Zend Engine was designed from the ground up for increased speed,
! 1026: reduced memory consumption and more reliable execution. We dare say
! 1027: it meets all of these goals and does so pretty well. Beyond that,
! 1028: there are several improvements in the language engine features:
! 1029:
! 1030: * References support.
! 1031:
! 1032: $foo = &$a; would make $foo and $a be two names to the same
! 1033: variable. This works with arrays as well, on either side; e.g.,
! 1034: $foo = &$a[7]; would make $foo and $a[7] be two names to the
! 1035: same variable. Changing one would change the other and vice
! 1036: versa.
! 1037:
! 1038: * Object overloading support.
! 1039:
! 1040: This feature allows various OO libraries to use the OO notation
! 1041: of PHP to access their functionality. Right now, no use is made
! 1042: of that feature, but we'd have a COM module ready by the time
! 1043: PHP 4.0 is released. A CORBA module would probably follow.
! 1044:
! 1045: * include() and eval() are now functions, and not statements.
! 1046:
! 1047: That means they return a value. The default return value from
! 1048: include() and eval() is 1, so that you can do if (include())
! 1049: without further coding. The return value may be changed by
! 1050: returning a value from the global scope of the included file or
! 1051: the evaluated string. For example, if 'return 7;' is executed in
! 1052: the global scope of foo.inc, include('foo.inc') would evaluate
! 1053: to 7.
! 1054:
! 1055: * Automatic resource deallocation.
! 1056:
! 1057: Several people have been bitten by the fact that PHP 3.0 had no
! 1058: concept of reference counting. The Zend Engine adds full
! 1059: reference counting for every value in the system, including
! 1060: resources. As soon as a resource is no longer referenced from
! 1061: any variable, it is automatically destroyed to save memory and
! 1062: resources. The most obvious example for the advantage in this is
! 1063: a loop that has an SQL query inside it, something like '$result
! 1064: = sql_query(...);'. In PHP 3.0, every iteration resulted in
! 1065: another SQL result-set allocated in the memory, and all of the
! 1066: result sets weren't destroyed until the end of the script's
! 1067: execution. With the Zend Engine, as soon as we overwrite an old
! 1068: result set with a new one, the old result set which is no longer
! 1069: referenced, is destroyed.
! 1070:
! 1071: * Full support for nesting arrays and objects within each other,
! 1072: in as many levels as you want.
! 1073:
! 1074: * true and false are now constants of type boolean.
! 1075:
! 1076: Comparing any other value to them would convert that value to a
! 1077: boolean first, and conduct the comparison later. That means, for
! 1078: example, that 5==true would evaluate to true (in PHP 3.0, true
! 1079: was nothing but a constant for the integer value of 1, so
! 1080: 5==true was identical to 5==1, which was false).
! 1081:
! 1082: * Runtime binding of function names.
! 1083:
! 1084: This complex name has a simple explanation - you can now call
! 1085: functions before they're declared!
! 1086:
! 1087: * Added here-docs support.
! 1088:
! 1089: * Added foreach.
! 1090:
! 1091: Two syntaxes supported:
! 1092:
! 1093: foreach(array_expr as $val) statement
! 1094: foreach(array_expr as $key => $val) statement
! 1095:
! 1096: * A true unset() implementation.
! 1097:
! 1098: A variable or element that is unset(), is now sent to oblivion
! 1099: in its entirely, no trace remains from it.
! 1100:
! 1101: * Output buffering support.
! 1102:
! 1103: Use ob_start() to begin output buffering, ob_end_flush() to end
! 1104: buffering and send out the buffered contents, ob_end_clean() to
! 1105: end buffering without sending the buffered contents, and
! 1106: ob_get_contents() to retreive the current contents of the output
! 1107: buffer. Header information (header(), content type, cookies) are
! 1108: not buffered. By turning on output buffering, you can
! 1109: effectively send header information all throughout your file,
! 1110: regardless of whether you've emitted body output or not.
! 1111:
! 1112: * Full variable reference within quoted strings:
! 1113:
! 1114: ${expr} - full indirect reference support for scalar
! 1115: variables
! 1116: {variable} - full variable support
! 1117:
! 1118: For example:
! 1119:
! 1120: $foo[5]['bar'] = 'foobar';
! 1121: print "{$foo[5]["bar"]}"; // would print "foobar"
! 1122:
! 1123: * Ability to call member functions of other classes from within
! 1124: member functions or from the global scope.
! 1125:
! 1126: You can now, for example, override a parent function with a
! 1127: child function, and call the parent function from it.
! 1128:
! 1129: * Runtime information for classes (class name, parent, available
! 1130: functions, etc.).
! 1131:
! 1132: * Much more efficient syntax highlighter - runs much quicker,
! 1133: performs more reliably, and generates much tighter HTML.
! 1134:
! 1135: * A full-featured debugger has been integrated with the language
! 1136: (supports breakpoints, expression evaluation, step-in/over,
! 1137: function call backtrace, and more).
! 1138:
! 1139: The Zend Engine claims 100% compatability with the engine of PHP
! 1140: 3.0, and is shamelessly lying about it. Here's why:
! 1141:
! 1142: * Static variable initializers only accept scalar values
! 1143: (in PHP 3.0 they accepted any valid expression). The impact
! 1144: should be somewhere in between void and non existent, since
! 1145: initializing a static variable with anything but a simple
! 1146: static value makes no sense at all.
! 1147:
! 1148: * The scope of break and continue is local to that of an
! 1149: include()'d file or an eval()'d string. The impact should
! 1150: be somewhat smaller of the one above.
! 1151:
! 1152: * The return statement no longer works from a require()'d file. It
! 1153: hardly worked in PHP 3.0, so the impact should be fairly small. If
! 1154: you want this functionality - use include() instead.
! 1155:
! 1156: * unset() is no longer a function, but a statement.
! 1157:
! 1158: * The following letter combination is not supported within
! 1159: encapsulated strings: "{$". If you have a string that includes
! 1160: this letter combination, for example, print "{$somevar"; (which
! 1161: printed the letter { and the contents of the variable $somevar in
! 1162: PHP 3.0), it will result in a parse error with the Zend Engine.
! 1163: In this case, you would have to change the code to print
! 1164: "\{$somevar"; This incompatability is due to the full variable
! 1165: reference within quoted strings feature added in the Zend
! 1166: Engine.
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>