|
|
The function names
__construct,
__destruct
(see Constructors and Destructors),
__call,
__get,
__set,
__isset,
__unset
(see Overloading),
__sleep,
__wakeup,
__toString,
__set_state,
__clone and
__autoload
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.
| Предостережение |
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.
|
serialize() checks if your class has a function with
the magic name __sleep. If so, that function is
executed 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 the object may have, commit pending
data or perform similar cleanup tasks. Also, the function is
useful if you have very large objects which do not need to be
saved completely.
Conversely, unserialize() checks for the
presence of a function with the magic name
__wakeup. If present, this function can
reconstruct any resources that the 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.
Пример 19-27. Sleep and 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()
{
mysql_close($this->link);
}
public function __wakeup()
{
$this->connect();
}
}
?>
|
|
The __toString method allows a class to decide
how it will react when it is converted to a string.
Пример 19-28. Simple example |
<?php
class TestClass
{
public $foo;
public function __construct($foo) {
$this->foo = $foo;
}
public function __toString() {
return $this->foo;
}
}
$class = new TestClass('Hello');
echo $class;
?>
|
Результат выполнения данного примера: |
It is worth noting that before PHP 5.2.0 the __toString
method was only called when it was directly combined with
echo() or print().
This static method is called
for classes exported by var_export() since PHP 5.1.0.
The only parameter of this method is an array containing exported
properties in the form array('property' => value, ...).
smoseley at transio dot com
30-Oct-2007 05:15
Suggestion: add a __toArray() magic method that would default as exportation of an object's properties in an associative array.
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');
?>
alejandro dot gama at gmail dot com
09-May-2007 03:09
There is a trick to store static attributes with the objects in the $_SESSION array:
<?
session_start();
class Classes{
private $name;
private $statics;
function __construct($name){
$this->name=$name;
$this->statics=array();
}
function setStatic($key,$value){
if(!is_resource($value))
$this->statics[$key]=$value;
}
function __wakeup(){
foreach($this->statics as $k=>$v)
eval($this->name."::\$".$k."=\$this->statics['".$k."'];");
unset($this);
}
}
class Object{
function __sleep(){
$name=get_class($this);
if(empty($_SESSION["_classes"]))
$_SESSION["_classes"]=array();
if(empty($_SESSION["_classes"][$name])){
$_SESSION["_classes"][$name]=new Classes($name);
$from_object=get_object_vars($this);
$from_class=get_class_vars($name);
if(count($from_object)>0)
foreach($from_object as $k=>$value)
if($clave=array_search($k,$from_class))
unset($from_class[$clave]);
if(count($from_class)>0)
foreach($from_class as $k=>$v)
$_SESSION["_classes"][$name]->setStatic($k,$v);
}
return $from_object;
}
}
?>
You must inherit all your objects from Object and when you save them in the session the static method from their classes will be store and restore to their original state.
You must have one object from each class (that has static attributes) stored in the session.
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 ;)
|