From 8eae786de0763564da8a6bc3e295d54000904d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20K=C3=B6hntopp?= Date: Thu, 17 May 2001 23:05:01 +0000 Subject: [PATCH] - Extended documentation for object orientation. This should now cover most, if not all features of PHP 4 object orientation, reflecting the greatly improved OO features in PHP 4. - The documentation for serialize() and unserialize() is still stating that class associations are lost. This is no longer true in PHP 4 and should be corrected. It is now 1am here. I am not going to fix that now, someone else should. git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@47730 c90b9560-bf6c-de11-be94-00142212c4b1 --- language/oop.xml | 512 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 476 insertions(+), 36 deletions(-) diff --git a/language/oop.xml b/language/oop.xml index eeb14fe7cc..e09d3fb3ca 100644 --- a/language/oop.xml +++ b/language/oop.xml @@ -41,11 +41,39 @@ class Cart { items from this cart. + + + The following cautionary note are valid for PHP4. + + + + The name stdClass is used interally by + Zend and is reserved. You cannot have a class named + stdClass in PHP. + + + + The function names __sleep and + __wakeup are magical in PHP classes. You + cannot have functions with these names in any of your + classes unless you want the magic functionality associated + with them. See below for more information. + + + + PHP reserves all function names starting with __ as magical. + It is recommended that you do not use function names with + __ in PHP unless you want some documented magic functionality. + + + In PHP 4, only constant initializers for var - variables are allowed. Use constructors for non-constant - initializers. + variables are allowed. To initialize variables with non-constant + values, you need an initialization function which is called + automatically when an object is being constructed from the + class. Such a function is called a constructor (see below). @@ -80,19 +108,85 @@ class Cart { -$cart = new Cart; -$cart->add_item("10", 1); + $cart = new Cart; + $cart->add_item("10", 1); + + $another_cart = new Cart; + $another_cart->add_item("0815", 3); - This creates an object $cart of the class Cart. The function - add_item() of that object is being called to add 1 item of article - number 10 to the cart. Classes can be extensions of - other classes. The extended or derived class has all variables and - functions of the base class and what you add in the extended - definition. This is done using the extends keyword. Multiple - inheritance is not supported. + This creates the objects $cart and $another_cart, both of + the class Cart. The function add_item() of the $cart object + is being called to add 1 item of article number 10 to the + $cart. 3 items of article number 0815 are being added to + $another_cart. + + + + Both, $cart and $another_cart, have functions add_item(), + remove_item() and a variable items. These are distinct functions and + variables. You can think of the objects as something like + directories in a filesystem, where you can have two different + files README.TXT, as long as they are in different directories, + and you'll have to type the full pathname in order to reach each + file from the toplevel directory. In PHP terms, the toplevel + directory would be the global namespace, and the pathname separator + would be ->. Thus, the names $cart->items and + $another_cart->items name two different variables. Note + that the variable is named $cart->items, not + $cart->$items, that is, a variable name in PHP has only a + single dollar sign. + + + + +// correct, single $ +$cart->items = array("10" => 1); + +// invalid, because $cart->$items becomes $cart->"" +$cart->$items = array("10" => 1); + +// correct, but may or may not be what was intended: +// $cart->$myvar becomes $ncart->items +$myvar = 'items'; +$cart->$myvar = array("10" => 1); + + + + + Within a class, you do not know under which name the object will + be accessible in your program: At the time the Cart class was + written, it was unknown that the object will be named $cart or + $another_cart later. Thus, you cannot write $cart->items within + the Cart class. Instead, in order to be able to access it's own + functions and variables from within a class, one can use the + pseudo-variable $this which can be read as 'my own' or + 'current object'. Thus, '$this->items[$artnr] += $num' can + be read as 'add $num to the $artnr counter of my own items + array' or 'add $num to the $artnr counter of the items array + within the current object'. + + + + + <literal>extends</literal> + + + Often you need classes with similar variables and functions + to another existing class. In fact, it is good practice to + define a generic class which can be used in all your + projects and adapt this class for the needs of each of your + specific projects. To facilitate this, Classes can be + extensions of other classes. The extended or derived class + has all variables and functions of the base class (this is + called 'inheritance' despite the fact that nobody died) and what + you add in the extended definition. It is not possible to + substract from a class, that is, to undefine any existing + functions or variables. An extended class is always dependent + on a single base class, that is, multiple inheritance is + not supported. Classes are extended using the keyword 'extends'. @@ -123,36 +217,30 @@ print $ncart->owner; // print the cart owners name $ncart->add_item ("10", 1); // (inherited functionality from cart) - - - Within functions of a class the variable $this means this - object. You have to use $this->something to access any variable or - function named something within your current object. Both in and - outside of the object you do not need a $ when accessing an object's - properties. - - - -$ncart->owner = "chris"; // no $ + -$ncart->$owner = "chris"; -// this is invalid because $ncart->$owner = $ncart->"" + + <literal>Constructors</literal> -$myvar = 'owner'; -$ncart->$myvar = "chris"; -// this is valid because $ncart->$myvar = $ncart->owner - - + + + In PHP3 and PHP4 constructors behave differently. The PHP4 + semantics are strongly preferred. + + Constructors are functions in a class that are automatically - called when you create a new instance of a class. A function - becomes a constructor when it has the same name as the class. + called when you create a new instance of a class. In PHP3, a + function becomes a constructor when it has the same name as + the class. In PHP4, a function becomes a constructor, when + it has the same name as the class it is defined in. +// Works in PHP3 and PHP4. class Auto_Cart extends Cart { function Auto_Cart () { $this->add_item ("10", 1); @@ -166,11 +254,14 @@ class Auto_Cart extends Cart { which initializes the cart with one item of article number "10" each time a new Auto_Cart is being made with "new". Constructors can also take arguments and these arguments can be optional, which - makes them much more useful. + makes them much more useful. To be able to still use the class + without parameters, all parameters to constructors should be + made optional by providing default values. +// Works in PHP3 and PHP4. class Constructor_Cart extends Cart { function Constructor_Cart ($item = "10", $num = 1) { $this->add_item ($item, $num); @@ -186,15 +277,364 @@ $default_cart = new Constructor_Cart; $different_cart = new Constructor_Cart ("20", 17); - + - For derived classes, the constructor of the parent class is not - automatically called when the derived class's constructor is - called. + In PHP3, derived classes and constructors have a number of + limitations. The following examples should be read carefully + to understand these limitations. + + + +class A { + function A() { + echo "I am the constructor of A.<br>\n"; + } +} + +class B extends A { + function C() { + "I am a regular function.<br>\n"; + } +} + +// no constructor is being called in PHP3. +$b = new B; + + + + + In PHP3, no constructor is being called in the above example. + The rule in PHP3 is: 'A constructor is a function of the same + name as the class.'. The name of the class is B, and there is + no function called B() in class B. Nothing happens. + + + + This is fixed in PHP4 by introducing another rule: If a class + has no constructor, the constructor of the base class is being + called, if it exists. The above example would have printed + 'I am the constructor of A.<br>' in PHP4. + + + + +class A { + function A() { + echo "I am the constructor of A.<br>\n"; + } + + function B() { + echo "I am a regular function named B in class A.<br>\n"; + echo "I am not a constructor in A.<br>\n"; + } +} + +class B extends A { + function C() { + echo "I am a regular function.<br>\n"; + } +} + +// This will call B() as a constructor. +$b = new B; + + + + + In PHP3, the function B() in class A will suddenly become a + constructor in class B, although it was never intended to be. + The rule in PHP3 is: 'A constructor is a function of the same + name as the class.'. PHP3 does not care if the function is + being defined in class B, or if it has been inherited. + + + + This is fixed in PHP4 by modifying the rule to: 'A constructor + is a function of the same name as the class it is being defined + in.'. Thus in PHP4, the class B would have no constructor function + of its own and the constructor of the base class would have been + called, printing 'I am the constructor of A.<br>'. + + + + + Neither PHP3 nor PHP4 call constructors of the base class + automatically from a constructor of a derived class. It is + your responsibility to propagate the call to constructors + upstream where appropriate. + + + + + + There are no destructors in PHP3 or PHP4. You may use + register_shutdown_function instead + to simulate most effects of destructors. + + + + + Destructors are functions that are called automatically + when a variable is destroyed, either with unset + or by simply going out of scope. There are no destructors + in PHP. + + + + <literal>::</literal> + + + + The following is valid for PHP4 only. + + + + + Sometimes it is useful to refer to functions and variables + in base classes or to refer to functions in classes that + have not yet any instances. The :: operator is being used + for this. + + + + +class A { + function example() { + echo "I am the original function A::example().<br>\n"; + } +} + +class B extends A { + function example() { + echo "I am the redefined function B::example().<br>\n"; + A::example(); + } +} + +// there is no object of class A. +// this will print +// I am the original function A::example().<br> +A::example(); + +// create an object of class B. +$b = new B; + +// this will print +// I am the redefined function B::example().<br> +// I am the original function A::example().<br> +$b->example(); + + + + + The above example calls the function example() in + class A, but there is no object of class A, so that + we cannot write $a->example() or similar. Instead we + call example() as a 'class function', that is, as a + function of the class itself, not any object of that + class. + + + + There are class functions, but there are no class variables. + In fact, there is no object at all at the time of the call. + Thus, a class function may not use any object variables (but + it can use local and global variables), and it may no use + $this at all. + + + + In the above example, class B redefines the function example(). + The original definition in class A is shadowed + and no longer available, unless you are refering specifically + to the implementation of example() in class A using the + ::-operator. Write A::example() to do this. + + + + In this context, there is a current object and it may + have object variables. Thus, when used from WITHIN an + object function, you may use $this and object variables. + + + + + + <literal>parent</literal> + + + You may find yourself writing code that refers to + variables and functions in base classes. This is + particularly true if your derived class is a refinement + or specialisation of code in your base class. + + + + Instead of using the literal name of the base class in your + code, you should be using the special name + parent, which refers to the name of your + base class as given in the extends + declation of your class. By doing this, you avoid using the + name of your base class in more than one place. Should + your inheritance tree change during implementation, the + change is easily made by simply changing the + extends declaration of your class. + + + + +class A { + function example() { + echo "I am A::example() and provide basic functionality.<br>\n"; + } +} + +class B extends A { + function example() { + echo "I am B::example and provide additional functionality().<br>\n"; + parent::example(); + } +} + +$b = new B; + +// This will call B::example(), which will in turn call A::example(). +$b->example(); + + + + + + Serializing objects - objects in sessions + + + + The following information is valid for PHP4 only. In + PHP3, an + + + + + serialize returns a string containing a + byte-stream representation of any value that can be stored in + PHP. unserialize can use this string to + recreate the original variable values. Using serialize to + save an object will save all variables in an object. The + functions in an object will not be saved, only the name of + the class. + + + + In order to be able to unserialize an + object, the class of that object needs to be defined. That + is, if you have an object $a of class A on page1.php and + serialize this, you'll get a string that refers to class A + and contains all values of variabled contained in $a. If + you want to be able to unserialize this on page2.php, + recreating $a of class A, the definition of class A must + be present in page2.php. This can be done for example + by storing the class defintion of class A in an include + file and including this file in both page1.php and page2.php. + + + + +classa.inc: + class A { + var $one = 1; + + function show_one() { + echo $this->one; + } + } + +page1.php: + include("classa.inc"); + + $a = new A; + $s = serialize($a); + // store $s somewhere where page2.php can find it. + $fp = fopen("store", "w"); + echo $s; + fclose($fp); + +page2.php: + // this is needed for the unserialize to work properly. + include("classa.inc"); + + $s = implode("", @file("store")); + unserialize($s); + + // now use the function show_one of the $a object. + $a->show_one(); + + + + + If you are using sessions and use session_register + to register objects, these objects are serialized automatically + at the end of each PHP page, and are unserialized automatically on + each of the following pages. This basically means that these objects + can show up on any of your pages once they become part of your + session. + + + + It is strongly recommended that you include the class + definitions of all such registered objects on all of your + pages, even if you do not actually use these classes on all + of your pages. If you don't and an object is being + unserialized without its class definition being present, it + will lose its class association and become an object of class + stdClass without any functions available + at all, that is, it will become quite useless. + + + + So if the in the example above $a became part of a session by + running session_register("a"), you should + include the file classa.inc on all of your + pages, not only page1.php and page2.php. + + + + + The magic functions <literal>__sleep</literal> and <literal>__wakeup</literal> + + + serialize checks if your class has a function with + the magic name __sleep. If so, that function is + being run prior to any serialization. It can clean up the object + and is supposed to return an array with the names of all variables + of that object that should be serialized. + + + + The intended use of __sleep is to close any + database connections that object may have, committing pending + data or perform similar cleanup tasks. Also, the function is + useful if you have very large objects which need not be + saved completely. + + + + Conversely, unserialize checks for the + presence of a function with the magic name + __wakeup. If present, this function can + reconstruct any ressources that object may have. + + + + The intended use of __wakeup is to + reestablish any database connections that may have been lost + during serialization and perform other reinitialization + tasks. + + References inside the constructor