mirror of
https://github.com/macintoshplus/doc-en.git
synced 2026-03-28 02:42:11 +01:00
git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@174277 c90b9560-bf6c-de11-be94-00142212c4b1
1164 lines
32 KiB
XML
1164 lines
32 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!-- $Revision: 1.56 $ -->
|
|
<chapter id="language.oop">
|
|
<title>Classes and Objects (PHP 4)</title>
|
|
|
|
<sect1 id="keyword.class">
|
|
<title><literal>class</literal></title>
|
|
<para>
|
|
A class is a collection of variables and functions working with
|
|
these variables. A class is defined using the following syntax:
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Cart {
|
|
var $items; // Items in our shopping cart
|
|
|
|
// Add $num articles of $artnr to the cart
|
|
|
|
function add_item($artnr, $num) {
|
|
$this->items[$artnr] += $num;
|
|
}
|
|
|
|
// Take $num articles of $artnr out of the cart
|
|
|
|
function remove_item($artnr, $num) {
|
|
if ($this->items[$artnr] > $num) {
|
|
$this->items[$artnr] -= $num;
|
|
return true;
|
|
} elseif ($this->items[$artnr] == $num) {
|
|
unset($this->items[$artnr]);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
This defines a class named Cart that consists of an associative
|
|
array of articles in the cart and two functions to add and remove
|
|
items from this cart.
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
You can <emphasis>NOT</emphasis> break up a class definition into
|
|
multiple files. You also can <emphasis>NOT</emphasis> break a class
|
|
definition into multiple PHP blocks, unless the break is within a method
|
|
declaration. The following will not work:
|
|
</simpara>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class test {
|
|
?>
|
|
<?php
|
|
function test() {
|
|
print 'OK';
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<simpara>
|
|
However, the following is allowed:
|
|
</simpara>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class test {
|
|
function test() {
|
|
?>
|
|
<?php
|
|
print 'OK';
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
</warning>
|
|
|
|
<simpara>
|
|
The following cautionary notes are valid for PHP 4.
|
|
</simpara>
|
|
|
|
<caution>
|
|
<simpara>
|
|
The name <literal>stdClass</literal> is used interally by
|
|
Zend and is reserved. You cannot have a class named
|
|
<literal>stdClass</literal> in PHP.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<caution>
|
|
<simpara>
|
|
The function names <literal>__sleep</literal> and
|
|
<literal>__wakeup</literal> 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.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<caution>
|
|
<simpara>
|
|
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.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<simpara>
|
|
In PHP 4, only constant initializers for <literal>var</literal>
|
|
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).
|
|
</simpara>
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Cart {
|
|
/* None of these will work in PHP 4. */
|
|
var $todays_date = date("Y-m-d");
|
|
var $name = $firstname;
|
|
var $owner = 'Fred ' . 'Jones';
|
|
/* Arrays containing constant values will, though. */
|
|
var $items = array("VCR", "TV");
|
|
}
|
|
|
|
/* This is how it should be done. */
|
|
class Cart {
|
|
var $todays_date;
|
|
var $name;
|
|
var $owner;
|
|
var $items = array("VCR", "TV");
|
|
|
|
function Cart() {
|
|
$this->todays_date = date("Y-m-d");
|
|
$this->name = $GLOBALS['firstname'];
|
|
/* etc. . . */
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Classes are types, that is, they are blueprints for actual
|
|
variables. You have to create a variable of the desired type with
|
|
the <literal>new</literal> operator.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$cart = new Cart;
|
|
$cart->add_item("10", 1);
|
|
|
|
$another_cart = new Cart;
|
|
$another_cart->add_item("0815", 3);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
This creates the objects <varname>$cart</varname> and
|
|
<varname>$another_cart</varname>, both of the class Cart. The function
|
|
add_item() of the <varname>$cart</varname> object is being called to add 1
|
|
item of article number 10 to the <varname>$cart</varname>. 3 items of
|
|
article number 0815 are being added to <varname>$another_cart</varname>.
|
|
</para>
|
|
|
|
<para>
|
|
Both, <varname>$cart</varname> and <varname>$another_cart</varname>, have
|
|
functions add_item(), remove_item() and a variable items. These are
|
|
distinct functions and variables. You can think of the objects as
|
|
something similar to directories in a filesystem. In a filesystem you can
|
|
have two different files <filename>README.TXT</filename>, as long as they are in different
|
|
directories. Just like with directories where you'll have to type the
|
|
full pathname in order to reach each file from the toplevel directory, you
|
|
have to specify the complete name of the function you want to call: In PHP
|
|
terms, the toplevel directory would be the global namespace, and the
|
|
pathname separator would be <literal>-></literal>. Thus, the names
|
|
<varname>$cart->items</varname> and
|
|
<varname>$another_cart->items</varname> name two different variables.
|
|
Note that the variable is named <varname>$cart->items</varname>, not
|
|
<varname>$cart->$items</varname>, that is, a variable name in PHP has
|
|
only a single dollar sign.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// 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 $cart->items
|
|
$myvar = 'items';
|
|
$cart->$myvar = array("10" => 1);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
Within a class definition, 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
|
|
<varname>$cart</varname> or <varname>$another_cart</varname> later. Thus,
|
|
you cannot write <varname>$cart->items</varname> within the Cart class
|
|
itself. Instead, in order to be able to access it's own functions and
|
|
variables from within a class, one can use the pseudo-variable
|
|
<varname>$this</varname> which can be read as 'my own' or 'current
|
|
object'. Thus, '<varname>$this->items[$artnr]</varname> +=
|
|
<varname>$num</varname>' can be read as 'add <varname>$num</varname> to
|
|
the <varname>$artnr</varname> counter of my own items array' or 'add
|
|
<varname>$num</varname> to the <varname>$artnr</varname> counter of the
|
|
items array within the current object'.
|
|
</para>
|
|
|
|
<note>
|
|
<para>
|
|
There are some nice functions to handle classes and objects. You might want
|
|
to take a look at the <link linkend="ref.classobj">Class/Object
|
|
Functions</link>.
|
|
</para>
|
|
</note>
|
|
</sect1>
|
|
|
|
<sect1 id="keyword.extends">
|
|
<title><literal>extends</literal></title>
|
|
|
|
<para>
|
|
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
|
|
subtract 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'.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Named_Cart extends Cart {
|
|
var $owner;
|
|
|
|
function set_owner ($name) {
|
|
$this->owner = $name;
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
This defines a class Named_Cart that has all variables and functions of
|
|
Cart plus an additional variable <varname>$owner</varname> and an
|
|
additional function set_owner(). You create a named cart the usual way and
|
|
can now set and get the carts owner. You can still use normal cart
|
|
functions on named carts:
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$ncart = new Named_Cart; // Create a named cart
|
|
$ncart->set_owner("kris"); // Name that cart
|
|
print $ncart->owner; // print the cart owners name
|
|
$ncart->add_item("10", 1); // (inherited functionality from cart)
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
This is also called a "parent-child" relationship. You create a class,
|
|
parent, and use <literal>extends</literal> to create a new class
|
|
<emphasis>based</emphasis> on the parent class: the child class. You can
|
|
even use this new child class and create another class based on this child
|
|
class.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Classes must be defined before they are used! If you want the class
|
|
<literal>Named_Cart</literal> to extend the class
|
|
<literal>Cart</literal>, you will have to define the class
|
|
<literal>Cart</literal> first. If you want to create another class called
|
|
<literal>Yellow_named_cart</literal> based on the class
|
|
<literal>Named_Cart</literal> you have to define
|
|
<literal>Named_Cart</literal> first. To make it short: the order in which
|
|
the classes are defined is important.
|
|
</para>
|
|
</note>
|
|
</sect1>
|
|
|
|
<sect1 id="language.oop.constructor">
|
|
<title><literal>Constructors</literal></title>
|
|
|
|
<caution>
|
|
<simpara>
|
|
In PHP 3 and PHP 4 constructors behave differently. The PHP 4
|
|
semantics are strongly preferred.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<para>
|
|
Constructors are functions in a class that are automatically
|
|
called when you create a new instance of a class with
|
|
<literal>new</literal>. In PHP 3, a
|
|
function becomes a constructor when it has the same name as
|
|
the class. In PHP 4, a function becomes a constructor, when
|
|
it has the same name as the class it is defined in - the
|
|
difference is subtle, but crucial (see below).
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Works in PHP 3 and PHP 4.
|
|
class Auto_Cart extends Cart {
|
|
function Auto_Cart() {
|
|
$this->add_item("10", 1);
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
This defines a class Auto_Cart that is a Cart plus a constructor
|
|
which initializes the cart with one item of article number "10"
|
|
each time a new Auto_Cart is being made with "new". Constructors
|
|
can take arguments and these arguments can be optional, which
|
|
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.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// Works in PHP 3 and PHP 4.
|
|
class Constructor_Cart extends Cart {
|
|
function Constructor_Cart($item = "10", $num = 1) {
|
|
$this->add_item ($item, $num);
|
|
}
|
|
}
|
|
|
|
// Shop the same old boring stuff.
|
|
|
|
$default_cart = new Constructor_Cart;
|
|
|
|
// Shop for real...
|
|
|
|
$different_cart = new Constructor_Cart("20", 17);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
You also can use the <literal>@</literal> operator to
|
|
<emphasis>mute</emphasis> errors occurring in the constructor, e.g.
|
|
<literal>@new</literal>.
|
|
</para>
|
|
|
|
<caution>
|
|
<simpara>
|
|
In PHP 3, derived classes and constructors have a number of
|
|
limitations. The following examples should be read carefully
|
|
to understand these limitations.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A {
|
|
function A() {
|
|
echo "I am the constructor of A.<br />\n";
|
|
}
|
|
}
|
|
|
|
class B extends A {
|
|
function C() {
|
|
echo "I am a regular function.<br />\n";
|
|
}
|
|
}
|
|
|
|
// no constructor is being called in PHP 3.
|
|
$b = new B;
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
In PHP 3, no constructor is being called in the above example.
|
|
The rule in PHP 3 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.
|
|
</para>
|
|
|
|
<para>
|
|
This is fixed in PHP 4 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 PHP 4.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
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;
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
In PHP 3, the function B() in class A will suddenly become a
|
|
constructor in class B, although it was never intended to be.
|
|
The rule in PHP 3 is: 'A constructor is a function of the same
|
|
name as the class.'. PHP 3 does not care if the function is
|
|
being defined in class B, or if it has been inherited.
|
|
</para>
|
|
|
|
<para>
|
|
This is fixed in PHP 4 by modifying the rule to: 'A constructor
|
|
is a function of the same name as the class it is being defined
|
|
in.'. Thus in PHP 4, 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 />'.
|
|
</para>
|
|
|
|
<caution>
|
|
<simpara>
|
|
Neither PHP 3 nor PHP 4 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.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<note>
|
|
<simpara>
|
|
There are no destructors in PHP 3 or PHP 4. You may use
|
|
<function>register_shutdown_function</function> instead
|
|
to simulate most effects of destructors.
|
|
</simpara>
|
|
</note>
|
|
|
|
<para>
|
|
Destructors are functions that are called automatically
|
|
when an object is destroyed, either with <function>unset</function>
|
|
or by simply going out of scope. There are no destructors
|
|
in PHP.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="keyword.paamayim-nekudotayim"><!-- :-) -->
|
|
<title>Scope Resolution Operator (<literal>::</literal>)</title>
|
|
|
|
<caution>
|
|
<simpara>
|
|
The following is valid for PHP 4 and later only.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
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();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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
|
|
<varname>$this</varname> at all.
|
|
</para>
|
|
|
|
<para>
|
|
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 referring specifically
|
|
to the implementation of example() in class A using the
|
|
::-operator. Write A::example() to do this (in fact, you
|
|
should be writing parent::example(), as shown in the next
|
|
section).
|
|
</para>
|
|
|
|
<para>
|
|
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
|
|
<varname>$this</varname> and object variables.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="keyword.parent">
|
|
<title><literal>parent</literal></title>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
Instead of using the literal name of the base class in your
|
|
code, you should be using the special name
|
|
<literal>parent</literal>, which refers to the name of your
|
|
base class as given in the <literal>extends</literal>
|
|
declaration 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
|
|
<literal>extends</literal> declaration of your class.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
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();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</sect1>
|
|
|
|
<sect1 id="language.oop.serialization">
|
|
<title>Serializing objects - objects in sessions</title>
|
|
|
|
<note>
|
|
<simpara>
|
|
In PHP 3, objects will lose their class association
|
|
throughout the process of serialization and unserialization.
|
|
The resulting variable is of type object, but has no class
|
|
and no methods, thus it is pretty useless (it has become
|
|
just like an array with a funny syntax).
|
|
</simpara>
|
|
</note>
|
|
|
|
<caution>
|
|
<simpara>
|
|
The following information is valid for PHP 4 only.
|
|
</simpara>
|
|
</caution>
|
|
|
|
<para>
|
|
<function>serialize</function> returns a string containing a
|
|
byte-stream representation of any value that can be stored in
|
|
PHP. <function>unserialize</function> 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.
|
|
</para>
|
|
|
|
<para>
|
|
In order to be able to <function>unserialize</function> an object, the
|
|
class of that object needs to be defined. That is, if you have an object
|
|
<varname>$a</varname> 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 <varname>$a</varname>. If you want to be able to unserialize
|
|
this on page2.php, recreating <varname>$a</varname> of class A, the
|
|
definition of class A must be present in page2.php. This can be done for
|
|
example by storing the class definition of class A in an include file and
|
|
including this file in both page1.php and page2.php.
|
|
</para>
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?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");
|
|
fwrite($fp, $s);
|
|
fclose($fp);
|
|
|
|
// page2.php:
|
|
|
|
// this is needed for the unserialize to work properly.
|
|
include("classa.inc");
|
|
|
|
$s = implode("", @file("store"));
|
|
$a = unserialize($s);
|
|
|
|
// now use the function show_one() of the $a object.
|
|
$a->show_one();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>
|
|
If you are using sessions and use <function>session_register</function>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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
|
|
<literal>stdClass</literal> without any functions available
|
|
at all, that is, it will become quite useless.
|
|
</para>
|
|
|
|
<para>
|
|
So if in the example above <varname>$a</varname> became part of a session
|
|
by running <literal>session_register("a")</literal>, you should include the
|
|
file <literal>classa.inc</literal> on all of your pages, not only page1.php
|
|
and page2.php.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="language.oop.magic-functions">
|
|
<title>The magic functions <literal>__sleep</literal> and <literal>__wakeup</literal></title>
|
|
|
|
<para>
|
|
<function>serialize</function> checks if your class has a function with
|
|
the magic name <literal>__sleep</literal>. 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.
|
|
</para>
|
|
|
|
<para>
|
|
The intended use of <literal>__sleep</literal> 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.
|
|
</para>
|
|
|
|
<para>
|
|
Conversely, <function>unserialize</function> checks for the
|
|
presence of a function with the magic name
|
|
<literal>__wakeup</literal>. If present, this function can
|
|
reconstruct any resources that object may have.
|
|
</para>
|
|
|
|
<para>
|
|
The intended use of <literal>__wakeup</literal> is to
|
|
reestablish any database connections that may have been lost
|
|
during serialization and perform other reinitialization
|
|
tasks.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="language.oop.newref">
|
|
<title>References inside the constructor</title>
|
|
<para>
|
|
Creating references within the constructor can lead to confusing
|
|
results. This tutorial-like section helps you to avoid problems.
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Foo {
|
|
function Foo($name) {
|
|
// create a reference inside the global array $globalref
|
|
global $globalref;
|
|
$globalref[] = &$this;
|
|
// set name to passed value
|
|
$this->setName($name);
|
|
// and put it out
|
|
$this->echoName();
|
|
}
|
|
|
|
function echoName() {
|
|
echo "<br />", $this->name;
|
|
}
|
|
|
|
function setName($name) {
|
|
$this->name = $name;
|
|
}
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
|
|
<para>
|
|
Let us check out if there is a difference between
|
|
<varname>$bar1</varname> which has been created using
|
|
the copy <literal>=</literal> operator and
|
|
<varname>$bar2</varname> which has been created using
|
|
the reference <literal>=&</literal> operator...
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
$bar1 = new Foo('set in constructor');
|
|
$bar1->echoName();
|
|
$globalref[0]->echoName();
|
|
|
|
/* output:
|
|
set in constructor
|
|
set in constructor
|
|
set in constructor */
|
|
|
|
$bar2 =& new Foo('set in constructor');
|
|
$bar2->echoName();
|
|
$globalref[1]->echoName();
|
|
|
|
/* output:
|
|
set in constructor
|
|
set in constructor
|
|
set in constructor */
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Apparently there is no difference, but in fact there is a
|
|
very significant one: <varname>$bar1</varname> and
|
|
<varname>$globalref[0]</varname> are _NOT_ referenced, they
|
|
are NOT the same variable. This is because "new" does not
|
|
return a reference by default, instead it returns a copy.
|
|
<note>
|
|
<simpara>
|
|
There is no performance loss (since PHP 4 and up use reference
|
|
counting) returning copies instead of references. On the
|
|
contrary it is most often better to simply work with copies
|
|
instead of references, because creating references takes some
|
|
time where creating copies virtually takes no time (unless none
|
|
of them is a large array or object and one of them gets changed
|
|
and the other(s) one(s) subsequently, then it would be wise to
|
|
use references to change them all concurrently).
|
|
</simpara>
|
|
</note>
|
|
To prove what is written above let us watch the code below.
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
// now we will change the name. what do you expect?
|
|
// you could expect that both $bar1 and $globalref[0] change their names...
|
|
$bar1->setName('set from outside');
|
|
|
|
// as mentioned before this is not the case.
|
|
$bar1->echoName();
|
|
$globalref[0]->echoName();
|
|
|
|
/* output:
|
|
set from outside
|
|
set in constructor */
|
|
|
|
// let us see what is different with $bar2 and $globalref[1]
|
|
$bar2->setName('set from outside');
|
|
|
|
// luckily they are not only equal, they are the same variable
|
|
// thus $bar2->name and $globalref[1]->name are the same too
|
|
$bar2->echoName();
|
|
$globalref[1]->echoName();
|
|
|
|
/* output:
|
|
set from outside
|
|
set from outside */
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Another final example, try to understand it.
|
|
|
|
<informalexample>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class A {
|
|
function A($i) {
|
|
$this->value = $i;
|
|
// try to figure out why we do not need a reference here
|
|
$this->b = new B($this);
|
|
}
|
|
|
|
function createRef() {
|
|
$this->c = new B($this);
|
|
}
|
|
|
|
function echoValue() {
|
|
echo "<br />","class ",get_class($this),': ',$this->value;
|
|
}
|
|
}
|
|
|
|
|
|
class B {
|
|
function B(&$a) {
|
|
$this->a = &$a;
|
|
}
|
|
|
|
function echoValue() {
|
|
echo "<br />","class ",get_class($this),': ',$this->a->value;
|
|
}
|
|
}
|
|
|
|
// try to understand why using a simple copy here would yield
|
|
// in an undesired result in the *-marked line
|
|
$a =& new A(10);
|
|
$a->createRef();
|
|
|
|
$a->echoValue();
|
|
$a->b->echoValue();
|
|
$a->c->echoValue();
|
|
|
|
$a->value = 11;
|
|
|
|
$a->echoValue();
|
|
$a->b->echoValue(); // *
|
|
$a->c->echoValue();
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
<para>
|
|
This example will output:
|
|
</para>
|
|
<screen>
|
|
<![CDATA[
|
|
class A: 10
|
|
class B: 10
|
|
class B: 10
|
|
class A: 11
|
|
class B: 11
|
|
class B: 11
|
|
]]>
|
|
</screen>
|
|
</informalexample>
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="language.oop.object-comparison">
|
|
<title>Comparing objects</title>
|
|
<para>
|
|
In PHP 4, objects are compared in a very simple manner, namely: Two object
|
|
instances are equal if they have the same attributes and values, and are
|
|
instances of the same class. Similar rules are applied when comparing two
|
|
objects using the identity operator (<literal>===</literal>).
|
|
</para>
|
|
<para>
|
|
If we were to execute the code in the example below:
|
|
<example>
|
|
<title>Example of object comparison in PHP 4</title>
|
|
<programlisting role='php'>
|
|
<![CDATA[
|
|
<?php
|
|
function bool2str($bool) {
|
|
if ($bool === false) {
|
|
return 'FALSE';
|
|
} else {
|
|
return 'TRUE';
|
|
}
|
|
}
|
|
|
|
function compareObjects(&$o1, &$o2) {
|
|
echo 'o1 == o2 : '.bool2str($o1 == $o2)."\n";
|
|
echo 'o1 != o2 : '.bool2str($o1 != $o2)."\n";
|
|
echo 'o1 === o2 : '.bool2str($o1 === $o2)."\n";
|
|
echo 'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
|
|
}
|
|
|
|
class Flag {
|
|
var $flag;
|
|
|
|
function Flag($flag=true) {
|
|
$this->flag = $flag;
|
|
}
|
|
}
|
|
|
|
class SwitchableFlag extends Flag {
|
|
|
|
function turnOn() {
|
|
$this->flag = true;
|
|
}
|
|
|
|
function turnOff() {
|
|
$this->flag = false;
|
|
}
|
|
}
|
|
|
|
$o = new Flag();
|
|
$p = new Flag(false);
|
|
$q = new Flag();
|
|
|
|
$r = new SwitchableFlag();
|
|
|
|
echo "Compare instances created with the same parameters\n";
|
|
compareObjects($o, $q);
|
|
|
|
echo "\nCompare instances created with different parameters\n";
|
|
compareObjects($o, $p);
|
|
|
|
echo "\nCompare an instance of a parent class with one from a subclass\n";
|
|
compareObjects($o, $r);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
We will see:
|
|
<screen>
|
|
Compare instances created with the same parameters
|
|
o1 == o2 : TRUE
|
|
o1 != o2 : FALSE
|
|
o1 === o2 : TRUE
|
|
o1 !== o2 : FALSE
|
|
|
|
Compare instances created with different parameters
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
|
|
Compare an instance of a parent class with one from a subclass
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
</screen>
|
|
Which is the output we will expect to obtain given the comparison rules
|
|
above. Only instances with the same values for their attributes and from the same
|
|
class are considered equal and identical.
|
|
</para>
|
|
<para>
|
|
Even in the cases where we have object composition, the same comparison
|
|
rules apply. In the example below we create a container class that stores
|
|
an associative array of <classname>Flag</classname> objects.
|
|
<example>
|
|
<title>Compound object comparisons in PHP 4</title>
|
|
<programlisting role='php'>
|
|
<![CDATA[
|
|
<?php
|
|
class FlagSet {
|
|
var $set;
|
|
|
|
function FlagSet($flagArr = array()) {
|
|
$this->set = $flagArr;
|
|
}
|
|
|
|
function addFlag($name, $flag) {
|
|
$this->set[$name] = $flag;
|
|
}
|
|
|
|
function removeFlag($name) {
|
|
if (array_key_exists($name, $this->set)) {
|
|
unset($this->set[$name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
$u = new FlagSet();
|
|
$u->addFlag('flag1', $o);
|
|
$u->addFlag('flag2', $p);
|
|
$v = new FlagSet(array('flag1'=>$q, 'flag2'=>$p));
|
|
$w = new FlagSet(array('flag1'=>$q));
|
|
|
|
echo "\nComposite objects u(o,p) and v(q,p)\n";
|
|
compareObjects($u, $v);
|
|
|
|
echo "\nu(o,p) and w(q)\n";
|
|
compareObjects($u, $w);
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
Which gives the expected output:
|
|
<screen>
|
|
Composite objects u(o,p) and v(q,p)
|
|
o1 == o2 : TRUE
|
|
o1 != o2 : FALSE
|
|
o1 === o2 : TRUE
|
|
o1 !== o2 : FALSE
|
|
|
|
u(o,p) and w(q)
|
|
o1 == o2 : FALSE
|
|
o1 != o2 : TRUE
|
|
o1 === o2 : FALSE
|
|
o1 !== o2 : TRUE
|
|
</screen>
|
|
</para>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"../../manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|