lovchy Sun May 23 12:30:39 2004 EDT
Modified files: /phpdoc/en/appendices migration5.xml Log: Changes in PHP5/Zend2 inserted into OOP section
http://cvs.php.net/diff.php/phpdoc/en/appendices/migration5.xml?r1=1.15&r2=1.16&ty=u Index: phpdoc/en/appendices/migration5.xml diff -u phpdoc/en/appendices/migration5.xml:1.15 phpdoc/en/appendices/migration5.xml:1.16 --- phpdoc/en/appendices/migration5.xml:1.15 Wed Apr 14 22:30:57 2004 +++ phpdoc/en/appendices/migration5.xml Sun May 23 12:30:39 2004 @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="iso-8859-1"?> -<!-- $Revision: 1.15 $ --> +<!-- $Revision: 1.16 $ --> <appendix id="migration5"> <title>Migrating from PHP 4 to PHP 5</title> <section id='migration5.changes'> <title>What has changed in PHP 5</title> <para> - PHP 5 and the integrated Zend Engine 2 have greatly improved PHP's + &php; 5 and the integrated Zend Engine 2 have greatly improved PHP's performance and capabilities, but great care has been taken to break as - little existing code as possible. So migrating your code from PHP 4 to 5 - should be very easy. Most existing PHP 4 code should be ready to run + little existing code as possible. So migrating your code from &php; 4 to 5 + should be very easy. Most existing &php; 4 code should be ready to run without changes, but you should still know about the <link linkend="migration5.incompatible">few differences</link> and take care to test your code before switching versions in production @@ -20,7 +20,7 @@ <section id="migration5.incompatible"> <title>Backward Incompatible Changes</title> <para> - Although most existing PHP 4 code should work without changes, you should + Although most existing &php; 4 code should work without changes, you should pay attention to the following backward incompatible changes: </para> <itemizedlist> @@ -40,7 +40,7 @@ </simpara></listitem> <listitem><simpara> PATH_TRANSLATED server variable is no longer set implicitly under - Apache2 SAPI in contrast to the situation in PHP 4, where it is set to + Apache2 SAPI in contrast to the situation in &php; 4, where it is set to the same value as the SCRIPT_FILENAME server variable when it is not populated by Apache. This change was made to comply with the <ulink url="&url.cgispecs;">CGI specification</ulink>. Please refer to <ulink @@ -49,11 +49,11 @@ <listitem><simpara> The <constant>T_ML_CONSTANT</constant> constant is no longer defined by the <link linkend="ref.tokenizer">Tokenizer</link> extension. If - error_reporting is set to <constant>E_ALL</constant>, PHP will generate a + error_reporting is set to <constant>E_ALL</constant>, &php; will generate a notice. Although the <constant>T_ML_CONSTANT</constant> was never used - at all, it was defined in PHP 4. In both PHP 4 and PHP 5 // and /* */ + at all, it was defined in &php; 4. In both &php; 4 and &php; 5 // and /* */ are resolved as the <constant>T_COMMENT</constant> constant. However the - PHPDoc style comments /** */ ,which starting PHP 5 are parsed by PHP, are + PHPDoc style comments /** */ ,which starting &php; 5 are parsed by &php;, are recognized as <constant>T_DOC_COMMENT</constant>. </simpara></listitem> <listitem><simpara> @@ -110,8 +110,8 @@ </example> </para> <para> - The following example was valid in PHP 4, although it will produce a fatal - error in PHP 5. + The following example was valid in &php; 4, although it will produce a fatal + error in &php; 5. </para> <para> <example> @@ -137,19 +137,19 @@ <section id="migration5.cli-cgi"> <title>CLI and CGI</title> <para> - In PHP 5 there were some changes in CLI and CGI filenames. In PHP 5, the + In &php; 5 there were some changes in CLI and CGI filenames. In &php; 5, the CGI version was renamed to <literal>php-cgi.exe</literal> (previously <literal>php.exe</literal>) and the CLI version now sits in the main directory (previously <literal>cli/php.exe</literal>). </para> <para> - In PHP 5 it was also introduced a new mode: + In &php; 5 it was also introduced a new mode: <literal>php-win.exe</literal>. This is equal to the CLI version, except that php-win doesn't output anything and thus provides no console (no "dos box" appears on the screen). This behavior is similar to php-gtk. </para> <para> - In PHP 5, the CLI version will always populate the global $argv and $argc + In &php; 5, the CLI version will always populate the global $argv and $argc variables. </para> </section> @@ -179,7 +179,7 @@ </informalexample> </para> <para> - If your webserver is running PHP in CGI mode, you should note that the + If your webserver is running &php; in CGI mode, you should note that the CGI version has changed its name from php.exe to php-cgi.exe. In Apache you should do something like this: <informalexample> @@ -203,7 +203,7 @@ <section id="migration5.functions"> <title>New Functions</title> <para> - In PHP 5 there are some new functions. Here is the list of them: + In &php; 5 there are some new functions. Here is the list of them: </para> <para>Arrays:</para> <itemizedlist> @@ -522,7 +522,7 @@ <section id="migration5.newconf"> <title>New Directives</title> <para> - There were some new &php.ini; directives introduced in PHP 5. Here is a + There were some new &php.ini; directives introduced in &php; 5. Here is a list of them: </para> <itemizedlist> @@ -534,7 +534,7 @@ </simpara></listitem> <listitem><simpara> <link linkend="ini.register-long-arrays">register_long_arrays</link> - - allow/disallow PHP to register the deprecated long $HTTP_*_VARS + allow/disallow &php; to register the deprecated long $HTTP_*_VARS </simpara></listitem> <listitem><simpara> <link linkend="ini.session.hash-function">session.hash_function</link> - @@ -547,7 +547,7 @@ binary hash data to something readable (from 4 to 6) </simpara></listitem> <listitem><simpara> - zend.ze1_compatibility_mode - Enable compatibility mode with Zend Engine 1 (PHP 4) + zend.ze1_compatibility_mode - Enable compatibility mode with Zend Engine 1 (&php; 4) </simpara></listitem> </itemizedlist> </section> @@ -555,10 +555,10 @@ <section id="migration5.databases"> <title>Databases</title> <para> - There were some changes in PHP 5 regarding databases (MySQL and SQLite). + There were some changes in &php; 5 regarding databases (MySQL and SQLite). </para> <para> - In PHP 5 the MySQL client libraries are not bundled, because of license + In &php; 5 the MySQL client libraries are not bundled, because of license problems and some others. For more information, read the <link linkend="faq.databases.mysql.php5">FAQ entry</link>. </para> @@ -567,24 +567,1107 @@ MySQL)</link>, which is designed to work with MySQL 4.1 and above. </para> <para> - Since PHP 5, the <link linkend="ref.sqlite">SQLite</link> extension is - built-in PHP. SQLite is an embeddable SQL database engine and is not a + Since &php; 5, the <link linkend="ref.sqlite">SQLite</link> extension is + built-in &php;. SQLite is an embeddable SQL database engine and is not a client library used to connect to a big database server (like MySQL or PostgreSQL). The SQLite library reads and writes directly to and from the database files on disk. </para> </section> + <section id='migration5.oop'> <title>New Object Model</title> <para> - In PHP 5 there is a new Object Model. PHP's handling of objects has been + In &php; 5 there is a new Object Model. PHP's handling of objects has been completely rewritten, allowing for better performance and more features. - Please read <ulink - url="http://www.php.net/zend-engine-2.php">http://www.php.net/zend-engine-2.php</ulink> - for more info. + In previous versions of &php;, objects were handled like primitive types + (for instance integers and strings). The drawback of this method was that + semantically the whole object was copied when a variable was assigned, or + pass as a parameter to a method. In the new approach, objects are + referenced by handle, and not by value (one can think of a handle as an + object's identifier). + </para> + <para> + Many &php; programmers aren't even aware of the copying quirks of the old + object model and, therefore, the majority of &php; applications will work + out of the box, or with very few modifications. </para> + + <section id='migration.oop.members'> + <title>Private and Protected Members</title> + <para> + &php; 5 introduces private and protected member variables, they allow you + to define the visibility of class properties. + </para> + <example> + <title>Private and Protected Members accesibility</title> + <simpara> + Protected member variables can be accessed in classes extending the + class they are declared in, whereas private member variables can only be + accessed by the class they belong to. + </simpara> + <programlisting role="php"> +<![CDATA[ +<?php +class MyClass { + private $Hello = "Hello, World!\n"; + protected $Bar = "Hello, Foo!\n"; + protected $Foo = "Hello, Bar!\n"; + + function printHello() { + print "MyClass::printHello() " . $this->Hello; + print "MyClass::printHello() " . $this->Bar; + print "MyClass::printHello() " . $this->Foo; + } +} + +class MyClass2 extends MyClass { + protected $Foo; + + function printHello() { + MyClass::printHello(); /* Should print */ + print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */ + print "MyClass2::printHello() " . $this->Bar; /* Shouldn't print (not declared)*/ + print "MyClass2::printHello() " . $this->Foo; /* Should print */ + } +} + +$obj = new MyClass(); +print $obj->Hello; /* Shouldn't print out anything */ +print $obj->Bar; /* Shouldn't print out anything */ +print $obj->Foo; /* Shouldn't print out anything */ +$obj->printHello(); /* Should print */ + +$obj = new MyClass2(); +print $obj->Hello; /* Shouldn't print out anything */ +print $obj->Bar; /* Shouldn't print out anything */ +print $obj->Foo; /* Shouldn't print out anything */ +$obj->printHello(); +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration.oop.methods'> + <title>Private and Protected Methods</title> + <para> + With &php; 5, private and protected methods are also introduced. + </para> + <example> + <title>Protected methods example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + private function aPrivateMethod() { + echo "Foo::aPrivateMethod() called.\n"; + } + + protected function aProtectedMethod() { + echo "Foo::aProtectedMethod() called.\n"; + $this->aPrivateMethod(); + } +} + +class Bar extends Foo { + public function aPublicMethod() { + echo "Bar::aPublicMethod() called.\n"; + $this->aProtectedMethod(); + } +} + +$o = new Bar; +$o->aPublicMethod(); +?> +]]> + </programlisting> + </example> + <simpara> + Old code that has no user-defined classes or functions named + "public", "protected" or "private" should + run without modifications. + </simpara> + </section> + + <section id='migration.oop.abstract'> + <title>Abstract Classes and Methods</title> + <para> + &php; 5 also introduces abstract classes and methods. An abstract method + only declares the method's signature and does not provide an + implementation. A class that contains abstract methods needs to be + declared abstract. + </para> + <example> + <title>Abstract class example</title> + <programlisting role="php"> +<![CDATA[ +<?php +abstract class AbstractClass { + abstract public function test(); +} + +class ImplementedClass extends AbstractClass { + public function test() { + echo "ImplementedClass::test() called.\n"; + } +} + +$o = new ImplementedClass; +$o->test(); +?> +]]> + </programlisting> + </example> + <simpara> + Abstract classes cannot be instantiated. Old code that has no + user-defined classes or functions named 'abstract' should run without + modifications. + </simpara> + </section> + + <section id='migration.oop.interfaces'> + <title>Interfaces</title> + <para> + &php; 5 introduces interfaces. A class may implement an arbitrary list of + interfaces. + </para> + <example> + <title>Interface example</title> + <programlisting role="php"> +<![CDATA[ +<?php +interface Throwable { + public function getMessage(); +} + +class MyException implements Throwable { + public function getMessage() { + // ... + } +} +?> +]]> + </programlisting> + </example> + <simpara> + Old code that has no user-defined classes or functions named 'interface' + or 'implements' should run without modifications. + </simpara> + </section> + + <section id='migration.oop.typehints'> + <title>Class Type Hints</title> + <para> + While remaining loosely typed &php; 5 introduces the ability to use class + type hints to declare the expected class of objects that are passed as + parameters to a method. + </para> + <example> + <title>Class type hinting example</title> + <programlisting role="php"> +<![CDATA[ +<?php +interface Foo { + function a(Foo $foo); +} + +interface Bar { + function b(Bar $bar); +} + +class FooBar implements Foo, Bar { + function a(Foo $foo) { + // ... + } + + function b(Bar $bar) { + // ... + } +} + +$a = new FooBar; +$b = new FooBar; + +$a->a($b); +$a->b($b); +?> +]]> + </programlisting> + </example> + <simpara> + These class type hints are not checked upon compilation, as would be the + case in a typed language, but during runtime. This means that: + </simpara> + <informalexample> + <programlisting role="php"> +<![CDATA[ +<?php +function foo(ClassName $object) { + // ... +} +?> +]]> + </programlisting> + </informalexample> + <simpara>is equivalent to:</simpara> + <informalexample> + <programlisting role="php"> +<![CDATA[ +<?php +function foo($object) { + if (!($object instanceof ClassName)) { + die("Argument 1 must be an instance of ClassName"); + } +} +?> +]]> + </programlisting> + </informalexample> + </section> + + <section id='migration5.oop.final'> + <title>final</title> + <para> + &php; 5 introduces the "final" keyword to declare final members and + methods. Methods and members declared final cannot be overridden by + sub-classes. + </para> + <example> + <title>final method</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + final function bar() { + // ... + } +} +?> +]]> + </programlisting> + </example> + <para> + It is furthermore possible to make a class final. Doing this prevents a + class from being specialized (it cannot be inherited by another class). + There's no need to declare the methods of a final class themselves as + final. + </para> + <example> + <title>final class</title> + <programlisting role="php"> +<![CDATA[ +<?php +final class Foo { + // class definition +} + +// the next line is impossible +// class Bork extends Foo {} +?> +]]> + </programlisting> + </example> + <para> + Properties can not be final. + </para> + <para> + Old code that has no user-defined classes or functions named 'final' + should run without modifications. + </para> + </section> + + <section id='migration5.oop.cloning'> + <title>Objects Cloning</title> + <para> + &php; 4 offered no way a user could decide what copy constructor to run + when an object is duplicated. During duplication, &php; 4 did a bit for bit + copy making an identical replica of all the object's properties. + </para> + <para> + Creating a copy of an object with fully replicated properties is not + always the wanted behavior. A good example of the need for copy + constructors, is if you have an object which represents a GTK window and + the object holds the resource of this GTK window, when you create a + duplicate you might want to create a new window with the same properties + and have the new object hold the resource of the new window. Another + example is if your object holds a reference to another object which it + uses and when you replicate the parent object you want to create a new + instance of this other object so that the replica has its own separate + copy. + </para> + <para> + An object copy is created by using the clone keyword (which calls the + object's <function>__clone</function> method if possible). An object's + <function>__clone</function> method cannot be called directly. + </para> + <para> + When the developer asks to create a new copy of an object, &php; 5 will + check if a <function>__clone</function> method has been defined or not. + If not, it will call a default __clone() which will copy all of the object's + properties. If a <function>__clone</function> method is defined, then it + will be responsible to set the necessary properties in the created object. + For convenience, the engine will supply a function that imports all of the + properties from the source object, so that they can start with a by-value + replica of the source object, and only override properties that need to be + changed. + </para> + <example> + <title>Objects cloning</title> + <programlisting role="php"> +<![CDATA[ +<?php +class MyCloneable { + static $id = 0; + + function MyCloneable() { + $this->id = self::$id++; + } + + function __clone() { + $this->address = "New York"; + $this->id = self::$id++; + } +} + +$obj = new MyCloneable(); + +$obj->name = "Hello"; +$obj->address = "Tel-Aviv"; + +print $obj->id . "\n"; + +$obj_cloned = clone $obj; + +print $obj_cloned->id . "\n"; +print $obj_cloned->name . "\n"; +print $obj_cloned->address . "\n"; +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.constructors'> + <title>Constructors</title> + <para> + &php; 5 allows developers to declare constructor methods for classes. + Classes which have a constructor method call this method on each + newly-created object, so it is suitable for any initialization that the + object may need before it is used. + </para> + <para> + With &php; 4, constructor methods were class methods that had the same name + as the class itself. Since it is very common to call parent constructors + from derived classes, the way &php; 4 worked made it a bit cumbersome to + move classes around in a large class hierarchy. If a class is moved to + reside under a different parent, the constructor name of that parent + changes as well, and the code in the derived class that calls the parent + constructor has to be modified. + </para> + <para> + &php; 5 introduces a standard way of declaring constructor methods by + calling them by the name <function>__construct</function>. + </para> + <example> + <title>using new unified constructors</title> + <programlisting role="php"> +<![CDATA[ +<?php +class BaseClass { + function __construct() { + print "In BaseClass constructor\n"; + } +} + +class SubClass extends BaseClass { + function __construct() { + parent::__construct(); + print "In SubClass constructor\n"; + } +} + +$obj = new BaseClass(); +$obj = new SubClass(); +?> +]]> + </programlisting> + </example> + <para> + For backwards compatibility, if &php; 5 cannot find a + <function>__construct</function> function for a given class, it will + search for the old-style constructor function, by the name of the class. + Effectively, it means that the only case that would have compatibility + issues is if the class had a method named + <function>__construct</function> which was used for different semantics. + </para> + </section> + + <section id='migration5.oop.destructors'> + <title>Destructors</title> + <para> + Having the ability to define destructors for objects can be very useful. + Destructors can log messages for debugging, close database connections + and do other clean-up work. No mechanism for object destructors existed + in &php; 4, although &php; had already support for registering functions + which should be run on request shutdown. + </para> + <para> + &php; 5 introduces a destructor concept similar to that of other + object-oriented languages, such as Java: When the last reference to an + object is destroyed the object's destructor, which is a class method + named <function>__destruct</function> that receives no parameters, is + called before the object is freed from memory. + </para> + <example> + <title>Destructor</title> + <programlisting role="php"> +<![CDATA[ +<?php +class MyDestructableClass { + function __construct() { + print "In constructor\n"; + $this->name = "MyDestructableClass"; + } + + function __destruct() { + print "Destroying " . $this->name . "\n"; + } +} + +$obj = new MyDestructableClass(); +?> +]]> + </programlisting> + </example> + <para> + Like constructors, parent destructors will not be called implicitly by + the engine. In order to run a parent destructor, one would have to + explicitly call <function>parent::__destruct</function> in the destructor + body. + </para> + </section> + + <section id='migration5.oop.constants'> + <title>Constants</title> + <para> + &php; 5 introduces per-class constants: + </para> + <example> + <title>Class constant example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + const constant = "constant"; +} + +echo "Foo::constant = " . Foo::constant . "\n"; +?> +]]> + </programlisting> + </example> + <simpara> + Old code that has no user-defined classes or functions named 'const' + will run without modifications. + </simpara> + </section> + + <section id='migration5.oop.exceptions'> + <title>Exceptions</title> + <para> + &php; 4 had no exception handling. &php; 5 introduces a exception model + similar to that of other programming languages. Note that there is + support for "catch all" but not for the "finally" clause. + </para> + <para> + Exceptions can be rethrown in catch blocks. Also it is possible to have + multiple catch blocks. In that case the caught exception is compared with + the classtype of each catch block from top to bottom and the first block + that has an 'instanceof' match gets executed. When the catch block + finishes, execution continues at the end of the last catch block. If no + catch block has an 'instanceof' match then the next try/catch block is + searched until no more try/catch blocks are available. In that case the + exception is an uncaught exception and the program terminates with + showing the exception. + </para> + <example> + <title>Exception creation example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class MyException { + function __construct($exception) { + $this->exception = $exception; + } + + function Display() { + print "MyException: $this->exception\n"; + } +} + +class MyExceptionFoo extends MyException { + function __construct($exception) { + $this->exception = $exception; + } + + function Display() { + print "MyException: $this->exception\n"; + } +} + +try { + throw new MyExceptionFoo('Hello'); +} +catch (MyException $exception) { + $exception->Display(); +} +catch (Exception $exception) { + echo $exception; +} +?> +]]> + </programlisting> + </example> + <para> + Even though the above example shows that it is possible to define + exception classes that don't inherit from Exception it is best to do so. + This is because the internal Exception class can gather a lot of + information otherwise not available. The &php; code emulation code would + look something like shown below. The comments show the meaning of each + property and hence their getter methods. As the code shows it is possible + to read any available information by using the getter methods. But since + some of the methods are used internally they are marked final. All in all + the class is very restrictive because it must be ensured that anything + used internally always works as expected. + </para> + <example> + <title>Base exceptions class</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Exception { + function __construct(string $message=NULL, int code=0) { + if (func_num_args()) { + $this->message = $message; + } + $this->code = $code; + $this->file = __FILE__; // of throw clause + $this->line = __LINE__; // of throw clause + $this->trace = debug_backtrace(); + $this->string = StringFormat($this); + } + + protected $message = 'Unknown exception'; // exception message + protected $code = 0; // user defined exception code + protected $file; // source filename of exception + protected $line; // source line of exception + + private $trace; // backtrace of exception + private $string; // internal only!! + + final function getMessage() { + return $this->message; + } + final function getCode() { + return $this->code; + } + final function getFile() { + return $this->file; + } + final function getTrace() { + return $this->trace; + } + final function getTraceAsString() { + return self::TraceFormat($this); + } + function _toString() { + return $this->string; + } + static private function StringFormat(Exception $exception) { + // ... a function not available in PHP scripts + // that returns all relevant information as a string + } + static private function TraceFormat(Exception $exception) { + // ... a function not available in PHP scripts + // that returns the backtrace as a string + } +} +?> +]]> + </programlisting> + </example> + <simpara> + If you derive your exception classes from this Exception base class your + exceptions will be nicely shown in the built-in handler for uncaught + exceptions. + </simpara> + <simpara> + Old code that has no user-defined classes or functions 'catch', 'throw' + and 'try' will run without modifications. + </simpara> + </section> + + <section id='migration5.oop.dereferencing'> + <title>Dereferencing objects returned from functions</title> + <para> + In &php; 4 it wasn't possible to dereference objects returned by functions + and make further method calls on those objects. With &php; 5, the following + is now possible: + </para> + <example> + <title>Dereferencing example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Circle { + function draw() { + print "Circle\n"; + } +} + +class Square { + function draw() { + print "Square\n"; + } +} + +function ShapeFactoryMethod($shape) { + switch ($shape) { + case "Circle": + return new Circle(); + case "Square": + return new Square(); + } +} + +ShapeFactoryMethod("Circle")->draw(); +ShapeFactoryMethod("Square")->draw(); +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.staticinit'> + <title>Static member variables initialization</title> + <para> + Static member variables of static classes can now be initialized. + </para> + <example> + <title>Static variable initialization example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class foo { + static $my_static = 5; + public $my_prop = 'bla'; +} + +print foo::$my_static; +$obj = new foo; +print $obj->my_prop; +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.staticmethods'> + <title>Static Methods</title> + <para> + &php; 5 introduces the 'static' keyword to declare a method static, thus + callable from outside the object context. + </para> + <example> + <title> Static Methods example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + public static function aStaticMethod() { + // ... + } +} + +Foo::aStaticMethod(); +?> +]]> + </programlisting> + </example> + <para> + The pseudo variable $this is not available inside a method that has been + declared static. + </para> + </section> + + <section id='migration5.oop.instanceof'> + <title>instanceof</title> + <para> + &php; 5 introduces the <literal>instanceof</literal> keyword, that + allows you to ascertain whether or not an object is an instance of + a class, or extends a class, or implements an interface. + </para> + <example> + <title><literal>instanceof</literal> example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class baseClass { } + +$a = new baseClass; + +if ($a instanceof baseClass) { + echo "Hello World"; +} +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.staticvars'> + <title>Static function variables</title> + <para> + Statics are now treated at compile-time which allows developers to + assign variables to statics by reference. This change also greatly + improves their performance but means that indirect references to statics + will not work anymore. + </para> + </section> + + <section id='migration5.oop.refparams'> + <title>Parameters passed by reference</title> + <para> + Parameters that are passed by reference to a function may now have + default values + </para> + <example> + <title /> + <programlisting role="php"> +<![CDATA[ +<?php +function my_function(&$var = null) { + if ($var === null) { + die("$var needs to have a value"); + } +} +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.autoload'> + <title><function>__autoload</function></title> + <para> + The <function>__autoload</function> interceptor function will be + automatically called when an undeclared class is to be instantiated. + The name of that class will be passed to the <function>__autoload</function> + interceptor function as its only argument. + </para> + <example> + <title><function>__autoload</function> example</title> + <programlisting role="php"> +<![CDATA[ +<?php +function __autoload($className) { + include_once $className . ".php"; +} + +$object = new ClassName; +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.overload'> + <title>Overloadable Method calls and Property accesses</title> + <para> + Both method calls and property accesses can be overloaded via the + <function>__call</function>, <function>__get</function> and + <function>__set</function> methods. + </para> + <example> + <title> + <function>__get</function> and + <function>__set</function> + </title> + <programlisting role="php"> +<![CDATA[ +<?php +class Setter { + public $n; + public $x = array("a" => 1, "b" => 2, "c" => 3); + + function __get($nm) { + print "Getting [$nm]\n"; + + if (isset($this->x[$nm])) { + $r = $this->x[$nm]; + print "Returning: $r\n"; + return $r; + } else { + print "Nothing!\n"; + } + } + + function __set($nm, $val) { + print "Setting [$nm] to $val\n"; + + if (isset($this->x[$nm])) { + $this->x[$nm] = $val; + print "OK!\n"; + } else { + print "Not OK!\n"; + } + } +} + + +$foo = new Setter(); +$foo->n = 1; +$foo->a = 100; +$foo->a++; +$foo->z++; +var_dump($foo); +?> +]]> + </programlisting> + </example> + <example> + <title><function>__get</function> example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Caller { + private $x = array(1, 2, 3); + + function __call($m, $a) { + print "Method $m called:\n"; + var_dump($a); + return $this->x; + } +} + +$foo = new Caller(); +$a = $foo->test(1, "2", 3.4, true); +var_dump($a); +?> +]]> + </programlisting> + </example> + </section> + + <section id='migration5.oop.iteration'> + <title>Iteration</title> + <para> + Objects may be iterated in an overloaded way when used with foreach. The + default behavior is to iterate over all properties. + </para> + <example> + <title>Object iteration example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + public $x = 1; + public $y = 2; +} + +$obj = new Foo; + +foreach ($obj as $prp_name => $prop_value) { + // using the property +} +?> +]]> + </programlisting> + </example> + <para> + Each class whose instances can be iterated with foreach should implement + the empty interface <literal>Traversable</literal>. Hence any object that + says it implements <literal>Traversable</literal> can be used with foreach. + </para> + <para> + The interfaces <literal>IteratorAggregate</literal> and <literal>Iterator</literal> + allows you to specify how class objects are iterated in &php; code. The first + of them simply has a method <function>getIterator</function> which must + return an array or an object that either implements the interface + <literal>Iterator</literal> or is instantiated from an internal + class that can be iterated + </para> + <example> + <title>Iterator creation example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class ObjectIterator implements Iterator { + + private $obj; + private $num; + + function __construct($obj) { + $this->obj = $obj; + } + function rewind() { + $this->num = 0; + } + function valid() { + return $this->num < $this->obj->max; + } + function key() { + return $this->num; + } + function current() { + switch($this->num) { + case 0: return "1st"; + case 1: return "2nd"; + case 2: return "3rd"; + default: return $this->num."th"; + } + } + function next() { + $this->num++; + } +} + +class Object implements IteratorAggregate { + + public $max = 3; + + function getIterator() { + return new ObjectIterator($this); + } +} + +$obj = new Object; + +// this foreach ... +foreach($obj as $key => $val) { + echo "$key = $val\n"; +} + +// matches the following 7 lines with the for directive. +$it = $obj->getIterator(); +for($it->rewind(); $it->hasMore(); $it->next) { + $key = $it->current(); + $val = $it->key(); + echo "$key = $val\n"; +} +unset($it); +?> +]]> + </programlisting> + </example> + </section> + + <section id='migrating5.oop.methodconst'> + <title><literal>__METHOD__</literal> constant</title> + <para> + The new <literal>__METHOD__</literal> pseudo constant shows the current + class and method when used inside a method and the function when used outside + of a class. + </para> + <example> + <title><literal>__METHOD__</literal> use example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + function show() { + echo __METHOD__; + } +} + +class Bar extends Foo { +} + +Foo::show(); // outputs Foo::show +Bar::show(); // outputs Foo::show either since __METHOD__ is + // compile-time evaluated token + +function test() { + echo __METHOD__; +} + +test(); // outputs test +?> +]]> + </programlisting> + </example> + </section> + + <section id='migrating5.oop.tostring'> + <title><function>__toString</function> method</title> + <para> + The new <function>__toString</function> magic method allows you to + overload the object to string conversion. + </para> + <example> + <title><function>__toString</function> example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + function __toString() { + return "What ever"; + } +} + +$obj = new Foo; + +echo $obj; // call __toString() +?> +]]> + </programlisting> + </example> + </section> + + <section id='migrating5.oop.reflection'> + <title>Reflection API</title> + <para> + &php; 5 comes with a complete reflection API that adds the ability to + reverse-engineer classes, interfaces, functions and methods as well as + extensions. + </para> + <para> + The reflection API also offers ways of getting doc comments for + functions, classes and methods. + </para> + <para> + Nearly all aspects of object oriented code can be reflected by using the + reflection API which is + <ulink url="http://sitten-polizei.de/php/reflection_api/docs/language.reflection.html"> + documented separately</ulink>. + </para> + <example> + <title>Reflection API use example</title> + <programlisting role="php"> +<![CDATA[ +<?php +class Foo { + public $prop; + function Func($name) { + echo "Hello $name"; + } +} + +reflection_class::export('Foo'); +reflection_object::export(new Foo); +reflection_method::export('Foo', 'func'); +reflection_property::export('Foo', 'prop'); +reflection_extension::export('standard'); +?> +]]> + </programlisting> + </example> + </section> + </section> + </appendix>