PHP
downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

finalキーワード> <パターン
Last updated: Fri, 09 Jan 2009

view this page in

マジックメソッド

以下の関数名 __construct, __destruct (コンストラクタとデストラクタ参照), __call, __callStatic, __get, __set, __isset, __unset (オーバーローディング参照), __sleep, __wakeup, __toString, __set_state および __clone は、PHP クラスにおける特殊関数の名前です。 これらの関数に関連する特別な機能を使用する場合を除き、 クラス内にこれらの名前を有する関数を作成してはいけません。

警告

PHP は、__ で始まる関数名を特殊関数として予約しています。 文書化された特殊な機能を必要とする場合を除き、 __ で始まる関数名を使用しないことが推奨されます。

__sleep__wakeup

serialize() は、クラスに特殊な名前 __sleep の関数があるかどうかを調べます。 もしあれば、シリアル化の前にその関数を実行します。 この関数で、オブジェクトをクリアすることができます。 またこの関数は、シリアル化するオブジェクトについて、 すべての変数の名前を配列で返すことが前提となっています。 このメソッドが何も返さなかった場合は、NULL がシリアル化され、E_NOTICE が発生します。

典型的な __sleep の使用法は、 途中のデータをコミットしたり、 似たようなタスクのクリアを行うといったものです。 また、オブジェクトが非常に大きく、かつ、完全に保存する必要がない場合、 この関数が有用です。

逆に、unserialize() は、 特殊な名前 __wakeup を有する 関数の存在を調べます。 もし存在する場合、この関数は、オブジェクトが有する可能性が あるあらゆるリソースを再構築することができます。

意図される __wakeup の使用法は、 シリアル化の際に失われたデータベース接続を再度確立したり、 その他の再初期化を行うことです。

例1 Sleep および wakeup

<?php
class Connection {
    protected 
$link;
    private 
$server$username$password$db;
    
    public function 
__construct($server$username$password$db)
    {
        
$this->server $server;
        
$this->username $username;
        
$this->password $password;
        
$this->db $db;
        
$this->connect();
    }
    
    private function 
connect()
    {
        
$this->link mysql_connect($this->server$this->username$this->password);
        
mysql_select_db($this->db$this->link);
    }
    
    public function 
__sleep()
    {
        return array(
'server''username''password''db');
    }
    
    public function 
__wakeup()
    {
        
$this->connect();
    }
}
?>

__toString

__toString メソッドにより、 クラスが文字列に変換される際の動作を決めることができます。

例2 簡単な例

<?php
// 簡単なクラスを宣言
class TestClass
{
    public 
$foo;

    public function 
__construct($foo) {
        
$this->foo $foo;
    }

    public function 
__toString() {
        return 
$this->foo;
    }
}

$class = new TestClass('Hello');
echo 
$class;
?>

上の例の出力は以下となります。

Hello

注意が必要なのは、PHP 5.2.0 より前では、 __toString メソッドは echo() または print(). と直接結合された場合のみコールされていたということです。 PHP 5.2.0 以降では、これはすべての文字列コンテキスト (たとえば printf() における %s 修飾子) でコールされます。しかし、その他の型のコンテキスト (たとえば %d 修飾子) ではコールされません。 PHP 5.2.0 以降では、__toString メソッドを持っていないオブジェクトを文字列に変換しようとすると E_RECOVERABLE_ERROR が発生します。

__set_state

この static メソッドは、 PHP 5.1.0 以降で var_export() によって エクスポートされたクラスのためにコールされます。

このメソッドの唯一のパラメータは、エクスポートされたプロパティを array('property' => value, ...) の形式で保持する配列です。

例3 __set_state の使用法 (PHP 5.1.0 以降)

<?php

class A
{
    public 
$var1;
    public 
$var2;

    public static function 
__set_state($an_array// PHP 5.1.0 以降
    
{
        
$obj = new A;
        
$obj->var1 $an_array['var1'];
        
$obj->var2 $an_array['var2'];
        return 
$obj;
    }
}

$a = new A;
$a->var1 5;
$a->var2 'foo';

eval(
'$b = ' var_export($atrue) . ';'); // $b = A::__set_state(array(
                                            //    'var1' => 5,
                                            //    'var2' => 'foo',
                                            // ));
var_dump($b);

?>

上の例の出力は以下となります。

object(A)#2 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
}


finalキーワード> <パターン
Last updated: Fri, 09 Jan 2009
 
add a note add a note User Contributed Notes
マジックメソッド
muratyaman at gmail dot com
07-Jan-2009 07:54
Regarding __toString:

<?php
class my_tag_A{

    public
$id='';
    public
$href='';
    public
$target='';
    public
$class='';
   
    public
$label='';
   
    function
__construct($href, $label){
       
$this->href = $href;
       
$this->label = $label;
    }
   
    public function
__toString(){
        return
'<a '.$this->nz_arr(array('id', 'href', 'target', 'class')). ' >' . $this->label . '</a>';
    }
   
    function
nz_arr($attrib_arr){
       
$s = '';
        foreach(
$attrib_arr as $attrib){
           
$s .= $this->nz($attrib);
        }
        return
$s;
    }

   
/**
     * Print the tag attribute if it is not blank, such as id="$this->id"
     * @param string $attrib
     * @return string
     */
   
function nz($attrib){
       
$s = '';
        if(
$this->$attrib != '') $s = $attrib .' = "' . $this->$attrib . '"';
        return
$s;
    }

   
//This causes RECURSION because of parsing between double quotes. This is a very UNEXPECTED behaviour!
   
function nz_($attrib){
       
$s = '';
        if(
$this->$attrib != '') $s = "$attrib = \"$this->$attrib\"";
        return
$s;
    }
   
}
//end  class

//usage
$a = new my_tag_A('abc.php', 'ABC'); $a->target = '_blank';
echo
$a;
//prints:
//    <a href="abc.php" target="_blank" >ABC</a>
?>
jsnell at e-normous dot com
03-Dec-2008 02:01
Be very careful to define __set_state() in classes which inherit from a parent using it, as the static __set_state() call will be called for any children.  If you are not careful, you will end up with an object of the wrong type.  Here is an example:

<?php
class A
{
    public
$var1;

    public static function
__set_state($an_array)
    {
       
$obj = new A;
       
$obj->var1 = $an_array['var1']; 
        return
$obj;
    }
}

class
B extends A {
}

$b = new B;
$b->var1 = 5;

eval(
'$new_b = ' . var_export($b, true) . ';');
var_dump($new_b);
/*
object(A)#2 (1) {
  ["var1"]=>
  int(5)
}
*/
?>
patricknegri at gmail dot com
26-Oct-2008 04:57
Imports Pattern - Extend Classes in Real Time:

<?php
class BaseClass
{
    var
$__imported;
    var
$__imported_functions;
   
    function
__construct()
    {
       
$__imported = Array();
       
$__imported_functions = Array();
    }
   
    function
Imports($object)
    {
       
$new_imports = new $object();
       
$imports_name = get_class($new_imports);
       
array_push( $__imported, Array($imports_name,$new_imports) );
       
$imports_function = get_class_methods($new_imports);
        foreach (
$imports_function as $i=>$function_name)
        {
           
$this->__imported_functions[$function_name] = &$new_imports;
        }       
    }
   
    function
__call($m, $a)
    {   
        if (
array_key_exists($m,$this->__imported_functions))
        {                   
            return
call_user_func_array(Array($this->__imported_functions[$m],$m),$a);
        }
        throw new
ErrorException ('Call to Undefined Method/Class Function', 0, E_ERROR);
    }
}

class
ExternalFunc
{
    function
TestB()
    {
        echo
"External Imported!";
    }
}

class
B extends BaseClass
{
    function
__construct()
    {
       
$this->Imports("ExternalFunc");
    }
   
    function
Msg()
    {
        echo
"Hello world<br />";
    }
}

$b = new B();
$b->Msg();
// or call $b->Imports("ExternalFunc");
$b->TestB();
//$b->TestB(1,3,4);
?>
jon at webignition dot net
03-Oct-2008 07:26
The __toString() method is extremely useful for converting class attribute names and values into common string representations of data (of which there are many choices). I mention this as previous references to __toString() refer only to debugging uses.

I have previously used the __toString() method in the following ways:

 - representing a data-holding object as:
   - XML
   - raw POST data
   - a GET query string
   - header name:value pairs

 - representing a custom mail object as an actual email (headers then body, all correctly represented)

When creating a class, consider what possible standard string representations are available and, of those, which would be the most relevant with respect to the purpose of the class.

Being able to represent data-holding objects in standardised string forms makes it much easier for your internal representations of data to be shared in an interoperable way with other applications.
wbcarts at juno dot com
02-Oct-2008 04:12
To be helpful, the __toString() method should return the class name and the state of all its properties inside square brackets.

<?php
class Point {
  protected
$x, $y;

  public function
__construct($xVal = 0, $yVal = 0) {
   
$this->x = $xVal;
   
$this->y = $yVal;
  }   

  public function
__toString() {      // the function we're interested in...
   
return "Point[x=$this->x, y=$this->y]";
  }
}

$point1 = new Point(10, 10);
$point2 = new Point(50, 50);
echo
$point1 . '<br>';
echo
$point2 . '<br><br>';
?>

Point[x=10, y=10]
Point[x=50, y=50]

Classes that include objects, should call that objects __toString() method.

<?php
class Line {
  protected
$start, $end;

  public function
__construct(Point $p1, Point $p2){
   
$this->start = $p1;
   
$this->end = $p2;
  }

  public function
__toString() {      // the function we're interested in...
   
return 'Line[start=' . $this->start->__toString() .  // call __toString()
    
', end=' . $this->end->__toString() . ']';          // call __toString()
 
}
}

echo (new
Line($point1, $point2));
?>

Line[start=Point[x=10, y=10], end=Point[x=50, y=50]]
rc @ nospam @ vorklift dot sea oh em
07-Aug-2008 07:03
A note: __wakeup occurs before saving the unserialization of an session object.

Therefore, $_SESSION['var']::__wakeup() setting $_SESSION['var'] = new Class() will fail and $_SESSION['var'] will remain unchanged.

This means that if you have a pseudo-temporary object that contains a class to auto revert to, you have to revert that session object in the initialization of the website rather than via a __wakeup() script.
Anonymous
31-May-2008 04:24
Serializing objects is problematic with references. This is solved redefining the __sleep() magic method. This is also problematic when parent class has private variables since the parent object is not accessible nor its private variables from within the child object.

I found a solution that seems working for classes that implements this __sleep() method, and for its subclasses. Without more work in subclasses. The inheritance system does the trick.

Recursively __sleep() call parent' __sleep() and return the whole array of variables of the object instance to be serialized.

<?php
class foo {
}

class
a {
  private
$var1;

  function
__construct(foo &$obj = NULL) {
   
$this->var1 = &$obj;
  }

 
/** Return its variables array, if its parent exists and the __sleep method is accessible, call it and push the result into the array and return the whole thing. */
 
public function __sleep() {
   
$a = array_keys(get_object_vars(&$this));
    if (
method_exists(parent, '__sleep')) {
     
$p = parent::__sleep();
     
array_push($a, $p);
    };
    return
$a;
  }
}

class
b extends a {
  function
__construct(foo &$obj = NULL) {
   
parent::__construct($obj);
  }
}

session_start();
$myfoo = &new foo();
$myb = &new b($myfoo);
$myb = unserialize(serialize(&$myb));
?>

This should work, I haven't tested deeper.
yanleech at gmail dot com
10-May-2008 06:24
Maybe we can using unserialize() & __wakeup() instead "new" when creating a new instance of class.

Consider following codes:

class foo
{
    static public $WAKEUP_STR = 'O:3:"foo":0:{}';
    public function foo(){}
    public function bar(){}
}

$foo = unserialize(foo::$WAKEUP_STR);
michal dot kocarek at seznam dot cz
18-Apr-2008 02:34
Remember that setters and getters (__set, __get) will work in your class as long as you NOT SET the property with given name.

If you still want to have the public property definition in the class source code (phpDocumentor, editor code completition, or any other reason) when using these magic methods, simply unset() your public properties inside the constructor.
__set/__get function will be called and code reader will see at first sight, which public properties are available.

Example:
<?php
class user {
  
/**
    * @var int Gets and sets the user ID
    */
  
public $UserID;
   private
$_userID;

   public function
__construct() {

     
// All the magic is in single line:
      // We unset public property, so our setters and getters
      // are used and phpDoc and editors with code completition are happy
     
unset($this->UserID);

   }

   public function
__set($key, $value) {
     
// assign value for key UserID to _userID property
  
}

   public function
__get($key) {
     
// return value of _userID for UserID property
  
}
}
?>
dhuseby domain getback tld com
29-Feb-2008 06:22
The above hint for using array_keys((array)$obj) got me investigating how to get __sleep to really work with object hierarchies.

With PHP 5.2.3, If you want to serialize an object that is part of an object hierarchy and you want to selectively serialize members (public, private, and protected) by manually specifying the array of members, there are a few simple rules for naming members that you must follow:

1. public members should be named using just their member name, like so:

<?php
class Foo {
    public
$bar;

    public function
__sleep() {
        return array(
"bar");
    }
}
?>

2. protected members should be named using "\0" . "*" . "\0" . member name, like so:

<?php
class Foo {
    protected
$bar;

    public function
__sleep() {
        return array(
"\0*\0bar");
    }
}
?>

3. private members should be named using "\0" . class name . "\0" . member name, like so:

<?php
class Foo {
    private
$bar;

    public function
__sleep() {
        return array(
"\0Foo\0bar");
    }
}
?>

So with this information let us serialize a class hierarchy correctly:

<?php

class Base {
    private
$foo = "foo_value";
    protected
$bar = "bar_value";

    public function
__sleep() {
        return array(
"\0Base\0foo", "\0*\0bar");
    }
}

class
Derived extends Base {
    public
$baz = "baz_value";
    private
$boo = "boo_value";

    public function
__sleep() {
       
// we have to merge our members with our parent's
       
return array_merge(array("baz", "\0Derived\0boo"), parent::__sleep());
    }
}

class
Leaf extends Derived {
    private
$qux = "qux_value";
    protected
$zaz = "zaz_value";
    public
$blah = "blah_value";

    public function
__sleep() {
       
// again, merge our members with our parent's
       
return array_merge(array("\0Leaf\0qux", "\0*\0zaz", "blah"), parent::__sleep());
    }
}

// test it
$test = new Leaf();
$s = serialize($test);
$test2 = unserialize($s);
echo
$s;
print_r($test);
print_r($test2);

?>

Now if you comment out all of the __sleep() functions and output the serialized string, you will see that the output doesn't change.  The most important part of course is that with the proper __sleep() functions, we can unserialize the string and get a properly set up object.

I hope this solves the mystery for everybody.  __sleep() does work, if you use it correctly :-)
andrew dot minerd at sellingsource dot com
08-Nov-2007 07:55
Until __sleep is "fixed" (here's hoping), a function that will return ALL members of a given object -- public, protected, AND private:

<?php
       
public function getPropertyNames(array $filter = NULL)
        {
           
$rc = new ReflectionObject($this);
           
$names = array();

            while (
$rc instanceof ReflectionClass)
            {
                foreach (
$rc->getProperties() as $prop)
                {
                    if (!
$filter || !in_array($prop->getName(), $filter))
                       
$names[] = $prop->getName();
                }

               
$rc = $rc->getParentClass();
            }

            return
$names;
        }
?>
amir_abiri at ipcmedia dot com
24-Jul-2007 04:58
Another small thing that is important to note about __sleep() and privte member variables:

<?php
class A
{
  private
$a;
 
  public function
__construct()
  {
   
$this->a = 1;
  }
}

class
B extends A
{
  protected
$b;
 
  public function
__construct()
  {
   
parent::__construct();
   
$this->b = 2;
  }
 
  function
__sleep()
  {
    return array(
'a', 'b');
  }
}

serialize(new B);
?>

result:
Notice: serialize(): "a" returned as member variable from __sleep() but does not exist in ...

To summerize: in a given class hierarchy in which parent classes contain private member variables, those variables are serialized when __sleep() is not defined. However, once __sleep() is defined, there is no way to make those private member variables serialized as well. From that point on, serialization is performed from the visibility scope of the subclass.

It is particularly important to note this little quirk when designing base classes that their derivables may be serialized, or when subclassing an external library class.
alejandro dot gama at gmail dot com
09-May-2007 07:47
Referering my previus note: there was an error in the code. But i find a better way:

<?
session_start
();

class
Classes{
  private
$name;
  private
$statics;
   
  function
__construct($name){
   
$this->name=$name;
   
$this->statics=array();
  }
   
  function
setStatic($k,$v){
    if(!
is_resource($v))
     
$this->statics[$k]=$v;
  }
   
   
  function
__wakeup(){
    foreach(
$this->statics as $k=>$v)
      eval(
$this->name."::\$".$k."=\$this->statics['".$k."'];");
  }
}

function
storeStaticAttributes(){
 
$classes=get_declared_classes();
  foreach(
$classes as $name){
   
$reflect=new ReflectionClass($name);

    if(
$reflect->isUserDefined()){
     
$statics=$reflect->getStaticProperties();

      if(empty(
$_SESSION["_classes"]))
       
$_SESSION["_classes"]=array();
           
      if(empty(
$_SESSION["_classes"][$name]))
       
$_SESSION["_classes"][$name]=new Classes($name);

      foreach(
$statics as $k=>$v)
       
$_SESSION["_classes"][$name]->setStatic($k,$v);   
    }
  }
}
register_shutdown_function('storeStaticAttributes');
?>
Travis Swicegood
08-May-2007 07:43
There is no need to use eval() to mimic mixins (i.e., multiple inheritance) within PHP 5.  You only need to:

<?php

class MyClass
{
    private
$_obj = null;
    public function
__construct($obj)
    {
       
$this->_obj = $obj;
    }

    public function
__call($method, $args)
    {
        if (!
method_exists($this->_obj, $method)) {
            throw new
Exception("unknown method [$method]");
        }

        return
call_user_func_array(
            array(
$this->_obj, $method),
           
$args
       
);
    }
}

?>

You could just as easily add an addMixin() method that would allow you to add multiple objects to an array, and then iterate over that array until you found the right method.  As noted, these are referred to as a Mixins in other languages.
adar at darkpoetry dot de
04-May-2007 06:09
Maybe not really new and all in all definitely not the best solution,but if you cant extend a class (if your class alreay extends an abstract or other things like that) you can 'fake' a extend.

<?php
class MyClass
       
extends SomeAbstractUnknownClass {

    private
$classObject;

    public function
__construct ( classObject $classToExtend ) {
       
$this->classObject = $classToExtend;
    }

    public function
__call($func, $var) {
        if ( !
count($var) ) {
            return
$this->classObject->$func($var);
        } else {
           
$str = '';
           
$values = array_values($var);
            for (
$i=0; $i<count($values); $i++ ) {
               
$str .= "'".$values[$i]."' ,";
            }  
           
$str = substr($str, 0, -2);
            return eval(
'return $this->classObject->'.$func.'('.$str.');');
        }  
    }  
}
?>

So if you'll do a $myClass->unknownMethod() and it is found neither in MyClass nor in SomeAbstractUnknownClass, MyClass will try to call this method in $classObject.

I use this for 'extending' a UserObject-Class which already extends an other one.

Better solutions are always welcome ;)
Dérico Filho
23-Jan-2007 07:33
Since PHP 5.2.0, you'll always get an error like this:
"Object of class foo could not be converted to string"

When one tries to use an object as string, for instance:

class Test{}
echo new Test();

Thus, one way to avoid this problem is to programme the magic method __toString.

However, in the older versions, it would output a string saying that it was an object together a unique obj id. Therefore, the __toString() method must comply with this behaviour.

My suggestion:

class Test{
    function __toString(){
        if(!isset($this->__uniqid))
            $this->__uniqid = md5(uniqid(rand(), true));
        return(get_class($this)."@".$this->__uniqid);
    }

}

echo new Test();

would output something like this:

Test@6006ba04f5569544c10a588b04849cf7
jstubbs at work-at dot co dot jp
02-Sep-2006 12:32
$myclass->foo['bar'] = 'baz';

When overriding __get and __set, the above code can work (as expected) but it depends on your __get implementation rather than your __set. In fact, __set is never called with the above code. It appears that PHP (at least as of 5.1) uses a reference to whatever was returned by __get. To be more verbose, the above code is essentially identical to:

$tmp_array = &$myclass->foo;
$tmp_array['bar'] = 'baz';
unset($tmp_array);

Therefore, the above won't do anything if your __get implementation resembles this:

function __get($name) {
    return array_key_exists($name, $this->values)
        ? $this->values[$name] : null;
}

You will actually need to set the value in __get and return that, as in the following code:

function __get($name) {
    if (!array_key_exists($name, $this->values))
        $this->values[$name] = null;
    return $this->values[$name];
}
taylorbarstow at google's mail service
15-May-2006 01:54
I've just come accross something interesting relating to storing PHP5 objects in a session.  If you don't provide an __autoload(), then you MUST load the class definition before calling session_start().  I guess that when you call session_start(), any objects in the session are unserialized then and there and placed into $_SESSION.  If you don't provide the class definition before calling session_start(), your object will get the class __PHP_Incomplete_Class, and you won't be able to use it for anything.

Examples:

<?php
session_start
();
require_once
'MyClass.php';
$obj = new MyClass;
$_SESSION['obj'] = $obj;
?>

Works fine.  Then on a subsequent page load:

<?php
session_start
();
require_once
'MyClass.php';
$_SESSION['obj']->callSomeMethod();
?>

Fatal error:  The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "MyClass" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide a __autoload() function to load the class definition.

But if you do this instead, it works fine:

<?php
require_once 'MyClass.php';
session_start();
$_SESSION['obj']->callSomeMethod();
?>

Hopefully in some future release of PHP, __PHP_Incomplete_Class will be smart enough to check for a class definition at time of use (method call or property operation), and, if the class exists, magically "complete" itself and turn into the desired object.
rayRO
02-Apr-2006 09:55
If you use the Magical Method '__set()', be shure that the call of
<?php
$myobject
->test['myarray'] = 'data';
?>
will not appear!

For that u have to do it the fine way if you want to use __set Method ;)
<?php
$myobject
->test = array('myarray' => 'data');
?>

If a Variable is already set, the __set Magic Method already wont appear!

My first solution was to use a Caller Class.
With that, i ever knew which Module i currently use!
But who needs it... :]
There are quiet better solutions for this...
Here's the Code:

<?php
class Caller {
    public
$caller;
    public
$module;

    function
__call($funcname, $args = array()) {
       
$this->setModuleInformation();

        if (
is_object($this->caller) && function_exists('call_user_func_array'))
           
$return = call_user_func_array(array(&$this->caller, $funcname), $args);
        else
           
trigger_error("Call to Function with call_user_func_array failed", E_USER_ERROR);
       
       
$this->unsetModuleInformation();
        return
$return;
    }

    function
__construct($callerClassName = false, $callerModuleName = 'Webboard') {
        if (
$callerClassName == false)
           
trigger_error('No Classname', E_USER_ERROR);

       
$this->module = $callerModuleName;

        if (
class_exists($callerClassName))
           
$this->caller = new $callerClassName();
        else
           
trigger_error('Class not exists: \''.$callerClassName.'\'', E_USER_ERROR);

        if (
is_object($this->caller))
        {
           
$this->setModuleInformation();
            if (
method_exists($this->caller, '__init'))
               
$this->caller->__init();
           
$this->unsetModuleInformation();
        }
        else
           
trigger_error('Caller is no object!', E_USER_ERROR);
    }

    function
__destruct() {
       
$this->setModuleInformation();
        if (
method_exists($this->caller, '__deinit'))
           
$this->caller->__deinit();
       
$this->unsetModuleInformation();
    }

    function
__isset($isset) {
       
$this->setModuleInformation();
        if (
is_object($this->caller))
           
$return = isset($this->caller->{$isset});
        else
           
trigger_error('Caller is no object!', E_USER_ERROR);
       
$this->unsetModuleInformation();
        return
$return;
    }

    function
__unset($unset) {
       
$this->setModuleInformation();
        if (
is_object($this->caller)) {
            if (isset(
$this->caller->{$unset}))
                unset(
$this->caller->{$unset});
        }
        else
           
trigger_error('Caller is no object!', E_USER_ERROR);
       
$this->unsetModuleInformation();
    }

    function
__set($set, $val) {
       
$this->setModuleInformation();
        if (
is_object($this->caller))
           
$this->caller->{$set} = $val;
        else
           
trigger_error('Caller is no object!', E_USER_ERROR);
       
$this->unsetModuleInformation();
    }

    function
__get($get) {
       
$this->setModuleInformation();
        if (
is_object($this->caller)) {
            if (isset(
$this->caller->{$get}))
               
$return = $this->caller->{$get};
            else
               
$return = false;
        }
        else
           
trigger_error('Caller is no object!', E_USER_ERROR);
       
$this->unsetModuleInformation();
        return
$return;
    }
   
    function
setModuleInformation() {
       
$this->caller->module = $this->module;
    }

    function
unsetModuleInformation() {
       
$this->caller->module = NULL;
    }
}

// Well this can be a Config Class?
class Config {
    public
$module;

    public
$test;

    function
__construct()
    {
        print(
'Constructor will have no Module Information... Use __init() instead!<br />');
        print(
'--> '.print_r($this->module, 1).' <--');
        print(
'<br />');
        print(
'<br />');
       
$this->test = '123';
    }
   
    function
__init()
    {
        print(
'Using of __init()!<br />');
        print(
'--> '.print_r($this->module, 1).' <--');
        print(
'<br />');
        print(
'<br />');
    }
   
    function
testFunction($test = false)
    {
        if (
$test != false)
           
$this->test = $test;
    }
}

echo(
'<pre>');
$wow = new Caller('Config', 'Guestbook');
print_r($wow->test);
print(
'<br />');
print(
'<br />');
$wow->test = '456';
print_r($wow->test);
print(
'<br />');
print(
'<br />');
$wow->testFunction('789');
print_r($wow->test);
print(
'<br />');
print(
'<br />');
print_r($wow->module);
echo(
'</pre>');
?>

Outputs something Like:

Constructor will have no Module Information... Use __init() instead!
-->  <--

Using of __init()!
--> Guestbook <--

123

456

789

Guestbook
ksamvel at gmail dot com
10-Feb-2006 09:29
To copy base part of derived class appropriate method in base should be defined. E.g.:

  class A {
    public function setAVar( $oAVar) { $this->oAVar = $oAVar; }
    public function getAVar() { return $this->oAVar; }

    public function copyA( &$roDest) {
      if( $roDest instanceof A)
        $this->oAVar = $roDest->oAVar;
    }

    private $oAVar;
  }

  class B extends A {
    public function setBVar( $oBVar) { $this->oBVar = $oBVar; }
    public function getBVar() { return $this->oBVar; }

    private $oBVar;
  }

  $oA = new A();
  $oB = new B();

  $oA->setAVar( 4);

  $oB->setAVar( 5);
  $oB->setBVar( 6);
  echo "oA::oAVar " . $oA->getAVar() . "<br>";
  echo "oB::oAVar " . $oB->getAVar() . "<br>";
  echo "oB::oBVar " . $oB->getBVar() . "<br>";
  echo "<br>";

  $oB->copyA( $oA);

  echo "oA::oAVar " . $oA->getAVar() . "<br>";
  echo "oB::oAVar " . $oB->getAVar() . "<br>";
  echo "oB::oBVar " . $oB->getBVar() . "<br>";

Output:

oA::oAVar 4
oB::oAVar 5
oB::oBVar 6

oA::oAVar 4
oB::oAVar 4
oB::oBVar 6
b dot schoppmeier at bas-consult dot de
26-Jan-2006 03:18
The sequence of events regarding __sleep and __destruct is unusual __ as __destruct is called before __sleep. The following code snippet:

<?php
$sequence
= 0;
class
foo {
    public
$stuff;   
    public function
__construct($param) {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - constructor\n";
       
$this->stuff = $param;
    }
    public function
__destruct() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - destructor\n";
    }
    public function
__sleep() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - __sleep\n";
        return array(
"stuff");
    }
    public function
__wakeup() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - __wakeup\n";
    }
}
session_start();
$_SESSION["obj"] = new foo("A foo");
?>

yields the output:

Seq: 0 - constructor
Seq: 1 - destructor
Seq: 2 - __sleep

Only when you end your script with a call to session_write_close() as in:

<?php
$sequence
= 0;
class
foo {
    public
$stuff;   
    public function
__construct($param) {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - constructor\n";
       
$this->stuff = $param;
    }
    public function
__destruct() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - destructor\n";
    }
    public function
__sleep() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - __sleep\n";
        return array(
"stuff");
    }
    public function
__wakeup() {
        global
$sequence;
        echo
"Seq: ", $sequence++, " - __wakeup\n";
    }
}
session_start();
$_SESSION["obj"] = new foo("A foo");
session_write_close();
?>

the sequence is as common sense would expect it to be as the following output shows:

Seq: 0 - constructor
Seq: 1 - __sleep
Seq: 2 - destructor
docey
09-Dec-2005 08:44
about __sleep and _wakeup, consider using a method like this:

class core
{

 var $sub_core; //ref of subcore
 var $_sleep_subcore; // place where serialize version of sub_core will be stored

 function core(){
  $this->sub_core = new sub_core();
  return true;
 }

 function __wakeup()
 {
  // on wakeup of core, core unserializes sub_core
  // wich it had stored when it was serialized itself
  $this->sub_core = unserialize($this->_sleep_subcore);
  return true;
 }

 function __sleep()
 {
  // sub_core will be serialized when core is serialized.
  // the serialized subcore will be stored as a string inside core.
   $this->_sleep_subcore = serialize($this->sub_core);
   $return_arr[] = "_sleep_subcore";
   return $return_arr;
 }

}

class sub_core
{
 var $info;

 function sub_core()
 {
  $this->info["somedata"] = "somedata overhere"
 }

 function __wakeup()
 {
  return true;
 }

 function __sleep()
 {
  $return_arr[] = "info"
  return $return_arr;
 }

}

this way subcore is being serialized by core when core is being serialized. subcore handles its own data and core stores it as a serialize string inside itself. on wakeup core unserializes subcore.

this may have a performance cost, but if you have many objects connected this way this is the best way of serializing them. you only need to serialize the the main object wich will serialize all those below which will serialize all those below them again. in effect causing a sort of chainreaction in wich each object takes care of its own info.

offcoarse you always need to store the eventualy serialized string in a safe place. somebody got experience with this way of __wakeup and __sleep.

works in PHP4&5
martin dot goldinger at netserver dot ch
15-Aug-2005 04:47
When you use sessions, its very important to keep the sessiondata small, due to low performance with unserialize. Every class shoud extend from this class. The result will be, that no null Values are written to the sessiondata. It will increase performance.

<?
class BaseObject
{
    function
__sleep()
    {
       
$vars = (array)$this;
        foreach (
$vars as $key => $val)
        {
            if (
is_null($val))
            {
                unset(
$vars[$key]);
            }
        }   
        return
array_keys($vars);
    }
};
?>
jeffxlevy at gmail dot com
13-Aug-2005 06:26
Intriguing what happens when __sleep() and __wakeup() and sessions() are mixed. I had a hunch that, as session data is serialized, __sleep would be called when an object, or whatever, is stored in _SESSION. true. The same hunch applied when session_start() was called. Would __wakeup() be called? True. Very helpful, specifically as I'm building massive objects (well, lots of simple objects stored in sessions), and need lots of automated tasks (potentially) reloaded at "wakeup" time. (for instance, restarting a database session/connection).
mastabog at hotmail dot com
12-Aug-2005 05:06
In reply to krisj1010 at gmail.com below:

__sleep() handles protected/private properties very well. You should never rely on get_class_vars() to retrieve property names since this function only returns the public properties. Use the Reflection API instead for that purpose. Better yet, if you know which ones you want to save it is always faster to specify the return array manually.
Domenic Denicola
23-Jun-2005 08:52
This small sentence tripped me up for a half an hour:

"It is worth noting that the __toString method will only be called when it is directly combined with echo() or print()."

So code like this will _not_ work, even though you might think it would:

<?

//$x is some variable with a __toString method defined.
$y = "x's value is: " . $x;
$y = "x's value is: " . (string)$x;

?>

In _em_ both situations, $y will contain "x's value is: Object id #42" (or whatever object ID). So, the only recourse I guess is this:

<?

$y
= "x's value is: " . $x->__toString();

?>
elias
11-Apr-2005 09:48
The default toString output is very useful for visual debuggin
because it shows the object id.
There is no function to resolve the id directly(?), but you
can do this:

<?php
function __toString()
{
   
sscanf((string)$this,