类与对象(PHP5)

php_manual学习之翻译:第19章 类与对象(PHP5)(连载)

[b]php_manual学习之翻译:第19章 类与对象(PHP5)之一:Visibility(访问控制)[/b]

    由于php手册从这一章节开始没有翻译,都是英文,近来自己开始学习php5中的面向对象编程,为方便学习和阅读,所以把其翻译之,发上来与大家分享,有不妥之处请大家批评指正!

    申请加精,我花了好长的时间来翻译的东西,呵呵~_~

     对属性或方法的访问控制,是通过在前面添加关键字 public、protected 或 private 来实现的。由 public 所定义的类成员可以在任何地方被访问;由 protected 所定义的类成员则可以被其所在类的子类和父类访问(当然,该成员所在的类也可以访问);而由 private 定义的类成员则只能被其所在类访问。
对类成员的访问控制
类成员都必须使用关键字public、protected 或 private 进行定义
例 10.9. 声明类成员
[php]
<?php
/**  Define MyClass  */
class MyClass
{  public $public = 'Public';
   protected $protected = 'Protected';
   private $private = 'Private';
   function printHello()
   {   echo $this->public;
       echo $this->protected;
        echo $this->private;
   }
}
$obj = new MyClass();
echo $obj->public; // // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello();// Shows Public, Protected and Priv
class MyClass2 extends MyClass  //Define MyClass2
{// We can redeclare the public and protected method, but not private
    protected $protected = 'Protected2';
    function printHello()
   {   echo $this->public;
       echo $this->protected;
       echo $this->private;
   }
}
$obj2 = new MyClass2();
echo $obj->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello();// Shows Public, Protected2, not Private
?>
[/php]
注意:
在 PHP 4 中使用 var 关键字对变量进行定义的方法在 PHP 5 的面向对象语法中不再使用。为了顾及兼容性,在类中定义一个变量的话,该变量会被自动设为 public,并且产生一个 E_STRICT 警告。
对方法的访问控制
类中的方法都必须使用关键字public、protected 或 private 进行定义。如果没有设置这些关键字,则该方法会被设置成默认的 public。
例 10.10. 声明类中的方法
[php]
<?php
class MyClass   //Define MyClass
{   public function __construct() { }
    public function MyPublic() { }
    protected function MyProtected() { }
    private function MyPrivate() { }
    function Foo()
   {   $this->MyPublic();
       $this->MyProtected();
       $this->MyPrivate();
   }
}
$myclass = new MyClass;
$myclass->MyPublic(); //
$myclass->MyProtected(); //
$myclass->MyPrivate(); //
$myclass->Foo();
class MyClass2 extends MyClass    //Define MyClass2
{  // This is public
   function Foo2()
   {   $this->MyPublic();
       $this->MyProtected();
       $this->MyPrivate();
   }
}
$myclass2 = new MyClass2;
$myclass2->MyPublic();
$myclass2->Foo2();
?>[/php]

[[i] 本帖最后由 forest 于 2006-5-4 22:06 编辑 [/i]]

2006-5-4 17:12 forest
第19章 类与对象(PHP5)之二:范围解析操作符(::)--Scope Resolution Operator (::)

范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是Zend开发小组在写Zend Engine 0.5(被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。
例 10.11. 在类的外部使用 :: 操作符
[php]
<?php
class MyClass
{   const CONST_VALUE = 'A constant value';
}
echo MyClass::CONST_VALUE;
?>[/php]
self和parent这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。
例 10.12. :: from inside the class definition
[php]
<?php
class OtherClass extends MyClass
{   public static $my_static = 'static var';
    public static function doubleColon()
    {   echo parent::CONST_VALUE . "/n";
       echo self::$my_static . "/n";
   }
}
OtherClass::doubleColon();
?>[/php]

当一个子类覆盖其父类中的方法时,PHP不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。这种机制也作用于构造函数和析构函数、重载及魔术函数。
例 10.13. 调用父类的方法
[php]
<?php
class MyClass
{    protected function myFunc() {    echo"MyClass::myFunc()/n";   }
}
class OtherClass extends MyClass
{  // Override parent's definition
   public function myFunc()
   {  // But still call the parent function
       parent::myFunc();
       echo "OtherClass::myFunc()/n";
   }
}
$class = new OtherClass();
$class->myFunc();
?>[/php]

[[i] 本帖最后由 forest 于 2006-5-4 17:53 编辑 [/i]]

2006-5-4 17:14 forest
第19章 类与对象(PHP5)之三:静态关键字(Static Keyword)

声明静态的类的成员和方法,使它不需要一个类的实例.一个static成员的声明不能通过一个类对象的实例来访问(尽管一个静态方法可以)。
静态声明必须在可见性声明之后。为了兼容PHP 4,如果没有可见性被声明,那么成员和方法将被当作是已经声明为public。
由于静态方法可以调用非对象实例,伪变量$this不可以在声明为静态的方法中使用。
事实上static方法调用形式在编译时被确定。当使用必须要声明的类名时,方法是完全标识和无继承规则的应用。当使用必须要声明的类名时,这种方法就被完全确认,而且没有使用继承的规则。
如果self已经被声明,那么self就被当前所属的类所解释。也不适用与继承规则。静态属性不能通过箭头操作符->.访问非静态方法,这将产生一个E_STRICT 级的警告。
例子 19-13. 静态成员的例子
[php]
<?php
class Foo
{   public static $my_static='foo';
    public function staticValue(){   return self::$my_static;   }
}
class Bar extends Foo
{   public function fooStatic(){   return parent::$my_static;   }
}
print Foo::$my_static."/n";
$foo = new Foo();
print $foo->staticValue()."/n";
print $foo->my_static."/n";// Undefined "Property" my_static
// $foo::my_static is not possible
print Bar::$my_static."/n";
$bar = new Bar();
print $bar->fooStatic()."/n";
?>[/php]
例子 19-14.静态方法实例(Static method example)
[php]
<?php
class Foo
{   public static function aStaticMethod() {    }
}
Foo::aStaticMethod();
?>[/php]

[[i] 本帖最后由 forest 于 2006-5-4 17:59 编辑 [/i]]

2006-5-4 17:26 forest
第19章 类与对象(PHP5)之四:类常量(Class Constants)

可以在每个基类中定义常量使它保持不变。在你不使用$符号去声明或使用它时,常量不同于普通变量。就象静态成员,常量值不能通过对象的实例来访问(而应使用$object::constant). 常量值必须是一个常量表达式,而不是一个变量,一个类的成员,一个数学表达式或函数调用的结果。
例子 19-15. 定义并使用一个常量
[php]
<?php
class MyClass
{   const constant = 'constant value';
    function showConstant() {   echo  self::constant."/n";   }
}
echo MyClass::constant."/n";
$class = new MyClass();
$class->showConstant();// echo $class::constant; is not allowed
?>
[/php]

[[i] 本帖最后由 forest 于 2006-5-4 18:01 编辑 [/i]]

2006-5-4 17:29 forest
第19章 类与对象(PHP5)之五:抽象类(Class Abstraction)

PHP 5中引入了抽象类和抽象方法。不允许创建一个已经定义为abstract的类的一个实例。任何至少包含一个抽象方法的类也必须是抽象的。被定义为抽象的方法仅仅是声明方法的一个信号,并不能定义它们的实现。
当从一个抽象类继承时,在父类中所有抽象方法的标记的声明必须通过子类定义;另外,这些方法必须用定义相同的访问属性。例如,如果方法被定义为protected类型,执行函数必须定义为protected或public.
例子 19-16. 抽象类例子
[php]
<?php
abstract class AbstractClass
{   // Force Extending class to define this method
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
    public function printOut()  // Common method
    {   
        print $this->getValue()."/n";
    }
}
class ConcreteClass1 extends AbstractClass
{   protected function getValue()
    {  
        return "ConcreteClass1";  
    }
    public function prefixValue($prefix)
    {
        return "{$prefix}ConcreteClass1";
    }
}
class ConcreteClass2 extends AbstractClass
{   public function getValue()
    {  
        return "ConcreteClass2";  
    }
    public function prefixValue($prefix)
    {
        return"{$prefix}ConcreteClass2";
    }
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."/n";
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."/n";
?>
[/php]
上例将输出:
[code]
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2[/code]
旧代码拥有非用户自定义的命名为abstract的类或函数将要运行如果没有被修改。

[[i] 本帖最后由 forest 于 2006-5-4 18:12 编辑 [/i]]

2006-5-4 17:44 forest
第19章 类与对象(PHP5)之六:对象接口(Object Interfaces)

对象接口允许你创建一个指定类的方法的执行代码,而不必说明这些方法是如何被操作(处理)的。
接口被用来定义接口关键字的使用,同样作为一个标准类,但没有任何方法有它们内容的定义。
在接口中所有的方法必须声明为public,这是接口的特性。
implements (执行,实现)
为了实现一个接口,使用了implements操作。在接口中所有的方法必须在一个类的内部实现;疏忽这些将导致一个致命错误。如果渴望通过使用一个逗号分开每个接口,类可以实现多个接口。
例子 19-17. 接口实例
[php]
<?php
// Declare the interface 'iTemplate'
interface iTemplate
{   public function setVariable($name, $var);
    public function getHtml($template);
}
// Implement the interface . This will work
class Template implements iTemplate
{   private $vars = array();
    public function setVariable($name,$var){  $this->vars[$name]=$var;  }
    public function getHtml($template)
    {   foreach($this->vars as $name => $value)
         {   $template = str_replace('{'.$name.'}',$value,$template);
        }
         return $template;
    }
}
//This will not work Fatal error:Class BadTemplate contains 1 abstract
//methos and must therefore be declared abstract (iTemplate::getHtml)
class BadTemplate implements iTemplate
{   private $vars = array();
    public function setVariable($name,$var){  $this->vars[$name] = $var;  }
}
?>[/php]

2006-5-4 17:58 forest
第19章 类与对象(PHP5)之七:重载(Overloading)

方法调用和成员访问都能通过__call,__get和__set方法被加载。这些方法将只有当你试图访问不包括成员或方法的对象或继承对象时触发。不是所有的重载方法都必须被定义为static.
从PHP 5.1.0开始也可以通过__isset()和__unset()方法逐个重载isset()和unset()函数。
成员函数重载(Member overloading)
void __set ( string name, mixed value )
mixed __get ( string name )
bool __isset ( string name )
void __unset ( string name )
类成员可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名变量,这些变量必须是被设置的或返回的。__set()方法的$value参数指定设置$name的对象的值。
例子 19-18.使用__get,__set,__isset和__unset重载的例子
[php]
<?php
class Setter
{   public $n;
    private $x = array("a" => 1, "b" => 2, "c" => 3);
    private function __get($nm)
    {   echo "Getting [$nm]/n";
        if (isset($this->x[$nm]))
         {   $r = $this->x[$nm];
            print "Returning: $r/n";
            return $r;
        } else {   echo "Nothing!/n";   }
    }
    private function __set($nm, $val)
    {   echo "Setting [$nm] to $val/n";
        if (isset($this->x[$nm]))
         {   $this->x[$nm] = $val;
            echo "OK!/n";
        } else {    echo "Not OK!/n";   }
    }
    private function __isset($nm)
    {   echo "Checking if $nm is set/n";
         return isset($this->x[$nm]);
    }
    private function __unset($nm)
    {   echo "Unsetting $nm/n";
        unset($this->x[$nm]);
    }
}
$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump(isset($foo->a)); //true
unset($foo->a);
var_dump(isset($foo->a)); //false
// this doesn't pass through the __isset() method
because 'n' is a public property
var_dump(isset($foo->n));
var_dump($foo);
?>[/php]
上例将输出:
[code]
Setting [a] to 100
OK!
Getting [a]
Returning: 100
Setting [a] to 101
OK!
Getting [z]
Nothing!
Setting [z] to 1
Not OK!
Checking if a is set
bool(true)
Unsetting a
Checking if a is set
bool(false)
bool(true)
object(Setter)#1 (2) {
  ["n"]=>int(1)["x:private"]=>array(2) {
["b"]=>
    int(2)
    ["c"]=>
    int(3)
  }
}[/code]
方法重载(Method overloading)
mixed __call ( string name, array arguments )
类方法可以通过定义这些指定的特定方法加载类中的自定义代码。$name参数被用来命名那些被请求的函数名。Arguments在定义为array的函数的$arguments参数中将被传递。从__call()方法返回的值将被返回方法的访问者。
例子 19-19.使用__call重载的实例
[php]
<?php
class Caller
{   private $x = array(1, 2, 3);
    public function __call($m, $a)
    {   print "Method $m called:/n";
        var_dump($a);
        return $this->x;
    }
}
$foo = new Caller();
$a = $foo->test(1, "2", 3.4, true);
var_dump($a);
?>[/php]
上例将输出:
[code]
Method test called:
array(4) {
    [0]=>
    int(1)
    [1]=>
    string(1) "2"
    [2]=>
   float(3.4)
    [3]=>
    bool(true)
}
array(3) {
    [0]=>
    int(1)
    [1]=>
    int(2)
    [2]=>
    int(3)
}[/code]

[[i] 本帖最后由 forest 于 2006-5-4 18:15 编辑 [/i]]

2006-5-4 18:11 forest
第19章 类与对象(PHP5)之八:对象迭代(Object Iteration)

PHP5提供一个为对象定义通过一连串的消息被重述的途径成为可能,例如使用一个foreach语句。默认地,所有可见的属性将用来迭代(反复)。
例子 19-20. 简单的对象迭代(Simple Object Iteration)
[php]
<?php
class MyClass
{   public $var1 = 'value 1';
    public $var2 = 'value 2';
    public $var3 = 'value 3';
    protected $protected = 'protected var';
    private   $private   = 'private var';
    function iterateVisible()
    {   echo "MyClass::iterateVisible:/n";
       foreach($this as $key => $value){  print "$key => $value/n";  }
    }
}
$class = new MyClass();
foreach($class as $key => $value){   print "$key => $value/n";  }
echo "/n";
$class->iterateVisible();
?>[/php]
如输出显示,foreach重述能通过全部可见变量被访问。更进一步,你可以实现一个PHP5的指定的内在接口迭代器(Iterator)。允许对象描述什么是对象重述和对象如何被重述的。
例子 19-21. 迭代器实现对象迭代(Object Iteration implementing Iterator)
[php]
<?php
class MyIterator implements Iterator
{   private $var = array();
    public function __construct($array)
    {   if (is_array($array)){  $this->var = $array; }
    }
    public function rewind()
    {    echo "rewinding/n";
        reset($this->var);
}
    public function current()
    {   $var = current($this->var);
        echo "current: $var/n";
        return $var;
    }
    public function key()
    {    $var = key($this->var);
        echo "key: $var/n";
        return $var;
    }
    public function next()
    {    $var = next($this->var);
        echo "next: $var/n";
        return $var;
    }
    public function valid()
    {    $var = $this->current() !== false;
        echo "valid: {$var}/n";
        return $var;
    }
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {  print "$a: $b/n";  }
?>[/php]
上例将输出:
[code]
rewinding
current: 1
valid: 1
current: 1
key: 0
0: 1
next: 2
current: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
current: 3
valid: 1
current: 3
key: 2
2: 3
next:
current:
valid: [/code]
在定义类时你也可以不必通过简单实现PHP5的IteratorAggregate接口定义所有的迭代器函数。
例19-22.IteratorAggregate对象迭代实现
[php]
<?php
class MyCollection implements IteratorAggregate
{   private $items = array();
    private $count = 0;
    // Required definition of interface IteratorAggregate
    public function getIterator()
    {    return new MyIterator($this->items);
    }
     public function add($value)
    {   
        $this->items[$this->count++] = $value;
    }
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val){  echo "key/value: [$key -> $val]/n/n";  }
?>[/php]
上例将输出:
[code]
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:[/code]

[[i] 本帖最后由 forest 于 2006-5-4 18:14 编辑 [/i]]

2006-5-4 18:18 forest
第19章 类与对象(PHP5)之九:模式(Patterns)

模式是最好的实践和设计的描述方法。它给普通的编程问题展示一个可变的解决方案。
工厂模式(Factory)
工厂模式允许在运行的时间实例化一个对象。自从工厂模式命名以来,制造一个对象是可能的。
例子 19-23.工厂方法 (Factory Method)
[php]
<?php
class Example
{   public static function factory($type)//The factory method
    {   if (include_once 'Drivers/'.$type.'.php')
         {    $classname = 'Driver_' . $type;
            return new $classname;
        }else{   throw new Exception ('Driver not found');  }
    }
}
?>[/php]
在类中允许定义一个驱动器在不工作时被加载的方法。如果类例子是一个数据库抽象类,可以象如下这样加载一个MySQL和SQLite驱动
[php]
<?php
$mysql = Example::factory('MySQL'); // Load a MySQL Driver
$sqlite = Example::factory('SQLite'); // Load a SQLite Driver
?>[/php]
单独模式(Singleton)
单模式适用于需要一个类的单独接口的情况。最普通的例子是数据库连接。这个模式的实现
允许程序员构造一个通过许多其他对象轻松地访问的单独接口。
例子 19-24.单模式函数(Singleton Function)
[php]
<?php
class Example
{   // Hold an instance of the class
    private static $instance;
    private function __construct()//A private constructor;prevents direct creation of object
    {   echo 'I am constructed';   }
     public static function singleton()// The singleton method
    {   if (!isset(self::$instance))
         {    $c = __CLASS__;
            self::$instance = new $c;
        }
        return self::$instance;
    }   
    // Example method
    public function bark() {   echo 'Woof!';   }
    // Prevent users to clone the instance
    public function __clone(){   trigger_error('Clone is not allowed.',E_USER_ERROR);  }
}
?>[/php]
允许类实例的一个单独接口被重新获得。
[php]
<?php
$test = new Example; // This would fail because the constructor is private
$test = Example::singleton();// This will always retrieve a single instance of the class
$test->bark();
$test_clone = clone($test); // This will issue an E_USER_ERROR.
?>[/php]

2006-5-4 18:21 forest
第19章 类与对象(PHP5) 之十:魔法方法(Magic Methods)

函数名__construct, __destruct (注意构造函数和析构函数), __call, __get, __set, __isset, __unset (注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload是PHP类里边的魔法函数.
函数名 __construct, __destruct(注意构造函数和析构函数), __call, __get, __set, __isset, __unset (see 注意重载), __sleep, __wakeup, __toString, __set_state, __clone and __autoload在PHP类里是魔术的.在任何类里你不能用这些名字给函数命名除非你想与它们的魔术功能性相关联。
    注意: PHP储量将所有用__开始的函数名作为魔术函数。推荐地,在PHP里不能用__做函数名除非你想用文件证明是魔术函数。
__sleep()和__wakeup()
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
例子 19-25. Sleep and wakeup
[php]
<?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();   }
}
?> [/php]
__toString
__toString方法允许一个类决定当它被修改为string类型时是如何起作用的。
例子 19-26.Simple example
[php]
<?php
class TestClass// Declare a simple class
{   public $foo;
    public function __construct($foo){  $this->foo = $foo;  }
    public function __toString()     {  return $this->foo;   }
}
$class = new TestClass('Hello');
echo $class;
?> [/php]
上例将输出:Hello
__toString方法将只在使用echo()和print()直接地组合时被调用是一个有效的注释方法。
例子 19-27. Cases where __toString is called
[php]
<?php
echo $class; //__toString called
echo 'text',$class; //__toString called (still a normal parameter for echo)
echo 'text'.$class; // __toString not called (concatenation operator used first)
echo (string)$class; //__toString not called (cast to string first)
echo "text $class";//__toString not called (cast to string first)
?>  [/php]
__set_state
从PHP 5.1.0开始static方法是通过var_export()函数来访问类接口的。这个方法的唯一参数是一个包含属性出口的以为array(‘property’=value,…)形式的数组

2006-5-4 18:24 forest
第19章:类与对象(PHP5)之十一:最终关键字(Final Keyword)

PHP5引入了最终关键字,防止子类使用final从一个重要的方法做定义的前缀。如果类本身已经被定义为final,类将不能被扩展。
例子 19-28.Final方法实例
[php]
<?php
class BaseClass
{   public function test()
    {   
        echo "BaseClass::test() called/n";  
    }
    final public function moreTesting()
    {
        echo"BaseClass::moreTesting() called/n";
    }
}
class ChildClass extends BaseClass
{
   public function moreTesting()
   {
       echo "ChildClass::moreTesting() called/n";
   }
}
//Results in Fatal error:Cannot override final method BaseClass::moreTesting()
?> [/php]

例子 19-29. Final 类实例
[php]
<?php
final class BaseClass
{    public function test()
     {  
         echo "BaseClass::test() called/n";  
     }
   //Here it doesn't matter if you specify the function as final or not
   final public function moreTesting()
   {
       echo"BaseClass::moreTesting() called/n";
   }
}
class ChildClass extends BaseClass {  }
//Results in Fatal error:Class ChildClass may not inherit from final class (BaseClass)
?>  [/php]

[[i] 本帖最后由 forest 于 2006-5-4 18:29 编辑 [/i]]

2006-5-4 18:28 forest
第19章 类与对象(PHP5)之十二:对象克隆(Object cloning)

通过完全地复制属性创建一个对象的拷贝不是通常想要的行为。需求的一个好的实例适合于拷贝构造函数,
如果有一个对象描述一个GTK窗口和对象保存这个GTK窗口的资源,当你创建一个副本,你或许想创建一个相同的属性新窗口使用和保存新对象资源的新窗口。另一个例子是当你复制父对象时如果保存一个引用给另一个对象,你想创建其他类的一个新实例来分开拷贝所属的复制品。一个对象的拷贝是使用clone关键字来创建的(如果可能的话可以调用对象的__clone()方法),一个对象的__clone()方法不能被直接声明。
[php] $copy_of_object = clone $object;[/php]
当一个对象被克隆时,PHP5将执行一个所有对象的属性的浅拷贝。任何对其它变量引用的属性将只保留引用。如果一个__clone()方法被定义,然后重新创建一个对象的克隆方法来允许任何必需的属性当它需要被改变时调用。
例子 19-30. 克隆一个对象
[php]
<?php
class SubObject
{   static $instances = 0;
    public $instance;
    public function __construct(){  $this->instance=++self::$instances;  }
    public function __clone() {  $this->instance=++self::$instances;  }
}
class MyCloneable
{   public $object1;
    public $object2;
    function __clone()
    {
       $this->object1=clone($this->object1);//Force a copy of this->object,otherwise it will point to same object.
    }
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("Original Object:/n");
print_r($obj);
print("Cloned Object:/n");
print_r($obj2);
?>[/php]
上例将输出:
[code]
Original Object:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 1
        )
    [object2] => SubObject Object
        (
            [instance] => 2
        )
)
Cloned Object:
MyCloneable Object
(
    [object1] => SubObject Object
        (
            [instance] => 3
        )
    [object2] => SubObject Object
        (
            [instance] => 2
        )
)[/code]

2006-5-4 18:31 forest
第19章:类与对象(PHP5)之十三:对象比较(Comparing objects)

在PHP5中,对象的比较比PHP4中的更复杂和更协调的期望的一个面向对象语言(倒不是说PHP5是这样的一门语言)。当使用比较操作符(==),对象变量以一种简单的方式被比较。也就是:如果它们具有相同的属性和值,两个对象的实例是相等,并且是同一个类的实例。
另一方面,当使用恒等式操作符(===)时,对象变量当且仅当它们引用同一个类的同一个实例时是相同的
一个例子就可以阐明这些规则
例子 19-31.PHP5中的对象比较实例
[php]
<?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
{   public $flag;
    function Flag($flag = true) {  $this->flag = $flag;  }
}
class OtherFlag
{   public $flag;
    function OtherFlag($flag = true) {  $this->flag = $flag;  }
}
$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();
echo "Two instances of the same class/n";
compareObjects($o, $p);
echo "/nTwo references to the same instance/n";
compareObjects($o, $q);
echo "/nInstances of two different classes/n";
compareObjects($o, $r);
?>[/php]
上例将输出:
[code]
Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
[/code]

2006-5-4 18:42 forest
第19章 类与对象(PHP5)之十四:映射(反射)Reflection

介绍(Introduction)
PHP 5与一个API完全映射来以增加反向工程师类,接口,函数和方法的效率(性能)并加以扩展。另外, API映射并且为函数,类和方法提供获取文档注释的方法。
API映射是对Zend引擎一个面向对象的扩展。包括以下类:
[php]
<?php
class Reflection { }
interface Reflector { }
class ReflectionException extends Exception { }
class ReflectionFunction implements Reflector { }
class ReflectionParameter implements Reflector { }
class ReflectionMethod extends ReflectionFunction { }
class ReflectionClass implements Reflector { }
class ReflectionObject extends ReflectionClass { }
class ReflectionProperty implements Reflector { }
class ReflectionExtension implements Reflector { }
?>[/php]  
注:为了详细了解这些类,请看下一章。 如果我们将执行如下例子的代码:
例子 19-32.API映射的基本用法
[php]
<?php
Reflection::export(new ReflectionClass('Exception'));
?>[/php]
上例将输出:
[code]
Class [ <internal> class Exception ] {
  - Constants [0] { }
  - Static properties [0] { }
  - Static methods [0] { }
  - Properties [6] {
    Property [ <default> protected $message ]
    Property [ <default> private $string ]
    Property [ <default> protected $code ]
    Property [ <default> protected $file ]
    Property [ <default> protected $line ]
    Property [ <default> private $trace ]
  }
  - Methods [9] {
    Method [ <internal> final private method __clone ] { }
    Method [ <internal> <ctor> public method __construct ] {
      - Parameters [2] {
        Parameter #0 [ <required> $message ]
        Parameter #1 [ <required> $code ]
      }
    }
    Method [ <internal> final public method getMessage ] {  }
    Method [ <internal> final public method getCode ] {  }
    Method [ <internal> final public method getFile ] {  }
    Method [ <internal> final public method getLine ] {  }
    Method [ <internal> final public method getTrace ] {  }
    Method [ <internal> final public method getTraceAsString ] { }
    Method [ <internal> public method __toString ] { }
  }
}[/code]
异常映射(ReflectionException)
ReflectionException 扩展标准异常并由API映射抛出。引入了非特定方法或属性。
映射函数(ReflectionFunction)
ReflectionFunction类允许你反向设计函数。
[php]
<?php
class ReflectionFunction implements Reflector
{
    final private __clone()
    public object __construct(string name)
    public string __toString()
    public static string export()
    public string getName()
    public bool isInternal()
    public bool isUserDefined()
    public string getFileName()
    public int getStartLine()
    public int getEndLine()
    public string getDocComment()
    public array getStaticVariables()
    public mixed invoke(mixed* args)
    public mixed invokeArgs(array args)
    public bool returnsReference()
    public ReflectionParameter[] getParameters()
    public int getNumberOfParameters()
    public int getNumberOfRequiredParameters()
}
?>[/php]
注:getNumberOfParameters()和getNumberOfRequiredParameters()在PHP5.0.3中增加,而invokeArgs()是在PHP5.1.0中增加。
为内省一个函数,您必须首先创建ReflectionFunction 类的一个实例。您可以随后访问这个实例中的任何上述方法。
例子 19-33. 使用ReflectionFunction 类
[php]
<?php
/** A simple counter
* @return  int  */
function counter()
{   static $c = 0;
    return $c++;
}
// Create an instance of the Reflection_Function class
$func = new ReflectionFunction('counter');
// Print out basic information
printf(
    "===> The %s function '%s'/n".
    "     declared in %s/n".
    "     lines %d to %d/n",
    $func->isInternal() ? 'internal' : 'user-defined',
    $func->getName(),
    $func->getFileName(),
    $func->getStartLine(),
    $func->getEndline()
);
// Print documentation comment
printf("--->Documentation:/n%s/n",var_export($func->getDocComment(),1));
if ($statics=$func->getStaticVariables())//Print static variables if existant
{  printf("--->Static variables:%s/n",var_export($statics,1));  }
printf("--->Invokation results in:");//Invoke the function
var_dump($func->invoke());
//you may prefer to use the export() method
echo "/nReflectionFunction::export() results:/n";
echo ReflectionFunction::export('counter');
?>[/php]
注:方法invoke()通过象call_user_func()这样的函数接受自变量的一个变化的数值。
映射参数 (ReflectionParameter)
ReflectionParameter类取回一个函数或方法的参数的信息。
[php]
<?php
class ReflectionParameter implements Reflector
{
    final private __clone()
    public object __construct(string name)
    public string __toString()
    public static string export()
    public string getName()
    public bool isPassedByReference()
    public ReflectionClass getClass()
    public bool isArray()
    public bool allowsNull()
    public bool isOptional()
    public bool isDefaultValueAvailable()
    public mixed getDefaultValue()
}
?>[/php]
注: 在PHP 5.0.3中增加了getDefaultValue(), isDefaultValueAvailable()和isOptional(),而isArray()则是在PHP5.1.0中增加的。
为内省函数参数,你必须首先创建ReflectionFunction或ReflectionMethod类的一个实例,然后用getParameters()方法来返回一个数组型参数。
例子 19-34. Using the ReflectionParameter class
[php]
<?php
function foo($a, $b, $c) { }
function bar(Exception $a, &$b, $c) { }
function baz(ReflectionFunction $a, $b = 1, $c = null) { }
function abc() { }
//通过命令行用给定的参数创建ReflectionFunction的一个实例   
$reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param)
{    printf( "-- Parameter #%d: %s {/n".
        "   Class: %s/n".
        "   Allows NULL: %s/n".
        "   Passed to by reference: %s/n".
        "   Is optional?: %s/n".
        "}/n",
        $i,
        $param->getName(),
        var_export($param->getClass(), 1),
        var_export($param->allowsNull(), 1),
        var_export($param->isPassedByReference(), 1),
        $param->isOptional() ? 'yes' : 'no');
}
?>[/php]
映射类(ReflectionClass)
ReflectionClass类允许你反向设计类。
[php]
<?php
class ReflectionClass implements Reflector
{   final private __clone()
    public object __construct(string name)
    public string __toString()
    public static string export()
    public string getName()
    public bool isInternal()
    public bool isUserDefined()
    public bool isInstantiable()
    public bool hasConstant(string name)
    public bool hasMethod(string name)
    public bool hasProperty(string name)
    public string getFileName()
    public int getStartLine()
    public int getEndLine()
    public string getDocComment()
    public ReflectionMethod getConstructor()
    public ReflectionMethod getMethod(string name)
    public ReflectionMethod[] getMethods()
    public ReflectionProperty getProperty(string name)
    public ReflectionProperty[] getProperties()
    public array getConstants()
    public mixed getConstant(string name)
    public ReflectionClass[] getInterfaces()
    public bool isInterface()
    public bool isAbstract()
    public bool isFinal()
    public int getModifiers()
    public bool isInstance(stdclass object)
    public stdclass newInstance(mixed* args)
    public ReflectionClass getParentClass()
    public bool isSubclassOf(ReflectionClass class)
    public array getStaticProperties()
    public mixed getStaticPropertyValue(string name [, mixed default])
    public void setStaticPropertyValue(string name, mixed value)
    public array getDefaultProperties()
    public bool isIterateable()
    public bool implementsInterface(string name)
    public ReflectionExtension getExtension()
    public string getExtensionName()
}
?>[/php]
注:PHP5.1.0中增加了hasConstant(), hasMethod(), hasProperty(), getStaticPropertyValue()和 setStaticPropertyValue()。
为了内省一个类,你必须首先创建ReflectionClass类的一个实例,你可以随后访问这个实例任何上述方法。
例子 19-35. 使用ReflectionClass 的类
[php]
<?php
interface Serializable  {    // ...}
class Object {    // ...}
/** A counter class */
class Counter extends Object implements Serializable
{   const START = 0;
    private static $c = Counter::START;
    /**Invoke counter
     * @access  public
     * @return  int */
    public function count() {  return self::$c++;  }
}
// Create an instance of the ReflectionClass class
$class = new ReflectionClass('Counter');
// Print out basic information
printf("===> The %s%s%s %s '%s' [extends %s]/n" .
    "     declared in %s/n" .
    "     lines %d to %d/n" .
    "     having the modifiers %d [%s]/n",
        $class->isInternal() ? 'internal' : 'user-defined',
        $class->isAbstract() ? ' abstract' : '',
        $class->isFinal() ? ' final' : '',
        $class->isInterface() ? 'interface' : 'class',
        $class->getName(),
        var_export($class->getParentClass(), 1),
        $class->getFileName(),
        $class->getStartLine(),
        $class->getEndline(),
        $class->getModifiers(),
        implode(' ', Reflection::getModifierNames($class->getModifiers()))
);
// Print documentation comment
printf("--->Documentation:/n %s/n",var_export($class->getDocComment(),1));
// Print which interfaces are implemented by this class
printf("--->Implements:/n %s/n",var_export($class->getInterfaces(),1));
// Print class constants
printf("--->Constants:%s/n",var_export($class->getConstants(),1));
// Print class properties
printf("--->Properties:%s/n",var_export($class->getProperties(),1));
// Print class methods
printf("--->Methods:%s/n",var_export($class->getMethods(),1));
// If this class is instantiable, create an instance
if ($class->isInstantiable())
{   $counter = $class->newInstance();
    echo '---> $counter is instance? ';
    echo $class->isInstance($counter) ? 'yes' : 'no';
    echo "/n---> new Object() is instance? ";
    echo $class->isInstance(new Object()) ? 'yes' : 'no';
}
?>[/php]
注:方法newInstance()通过象call_user_func()这样的函数接受自变量的一个变化的数值。
注:$class=new ReflectionClass('Foo');$class->isInstance($arg)等价于$arg instanceof Foo或is_a($arg, 'Foo').
映射方法(ReflectionMethod)
ReflectionMethod类允许你反向设计类方法。
[php]
<?php
class ReflectionMethod extends ReflectionFunction
{   public __construct(mixed class, string name)
    public string __toString()
    public static string export()
    public mixed invoke(stdclass object, mixed* args)
    public mixed invokeArgs(stdclass object, array args)
    public bool isFinal()
    public bool isAbstract()
    public bool isPublic()
    public bool isPrivate()
    public bool isProtected()
    public bool isStatic()
    public bool isConstructor()
    public bool isDestructor()
    public int getModifiers()
    public ReflectionClass getDeclaringClass()
    // Inherited from ReflectionFunction
    final private __clone()
    public string getName()
    public bool isInternal()
    public bool isUserDefined()
    public string getFileName()
    public int getStartLine()
    public int getEndLine()
    public string getDocComment()
    public array getStaticVariables()
    public bool returnsReference()
   public ReflectionParameter[] getParameters()
    public int getNumberOfParameters()
    public int getNumberOfRequiredParameters()
}
?>[/php]
为了内省一个方法,你必须首先创建ReflectionMethod类的一个实例。你可以随后访问这个实例任何上述方法。
例子 19-36. Using the ReflectionMethod class
[php]
<?php
class Counter
{    private static $c = 0;
    /** Increment counter
     * @final
     * @static
     * @access  public
     * @return  int */    final public static function increment(){ return ++self::$c; }
}
// Create an instance of the Reflection_Method class
$method = new ReflectionMethod('Counter','increment');
// Print out basic information
printf( "===> The %s%s%s%s%s%s%s method '%s' (which is %s)/n" .
    "     declared in %s/n" .
    "     lines %d to %d/n" .
    "     having the modifiers %d[%s]/n",
        $method->isInternal() ? 'internal' : 'user-defined',
        $method->isAbstract() ? ' abstract' : '',
        $method->isFinal() ? ' final' : '',
        $method->isPublic() ? ' public' : '',
        $method->isPrivate() ? ' private' : '',
        $method->isProtected() ? ' protected' : '',
        $method->isStatic() ? ' static' : '',
        $method->getName(),
        $method->isConstructor() ? 'the constructor' : 'a regular method',
        $method->getFileName(),
        $method->getStartLine(),
        $method->getEndline(),
        $method->getModifiers(),
        implode(' ', Reflection::getModifierNames($method->getModifiers()))
);
// Print documentation comment
printf("--->Documentation:/n %s/n",var_export($method->getDocComment(),1));
if($statics=$method->getStaticVariables())//Print static variables if existant
{ printf("--->Static variables:%s/n",var_export($statics,1)); }
printf("--->Invokation results in: ");//Invoke the method
var_dump($method->invoke(NULL));
?>[/php]
注:试图调用私有的,保护的或抽象的方法将导致被invoke()方法抛出一个异常。静态方法如上所视,你必须通过NULL作为第一个自变量来invoke()。而非静态方法通过类的实例来调用。
映射属性(ReflectionProperty)
ReflectionProperty类允许你反向设计类属性。
[php]
<?php
class ReflectionProperty implements Reflector
{   final private __clone()
    public __construct(mixed class, string name)
    public string __toString()
    public static string export()
    public string getName()
    public bool isPublic()
    public bool isPrivate()
    public bool isProtected()
    public bool isStatic()
    public bool isDefault()
    public int getModifiers()
    public mixed getValue(stdclass object)
    public void setValue(stdclass object, mixed value)
    public ReflectionClass getDeclaringClass()
    public string getDocComment()
}
?>[/php]
注: 在PHP 5.1.0中增加了getDocComment()方法。
为了内省一个属性,你必须首先创建ReflectionProperty类的一个实例,你可以随后访问这个实例的任何上述方法。
例子 19-37. Using the ReflectionProperty class
[php]
<?php
class String
{   public $length  = 5;   }
// Create an instance of the ReflectionProperty class
$prop=new ReflectionProperty('String','length');
// Print out basic information
printf( "===> The%s%s%s%s property '%s' (which was %s)/n" .
    "   having the modifiers %s/n",
        $prop->isPublic() ? ' public' : '',
        $prop->isPrivate() ? ' private' : '',
        $prop->isProtected() ? ' protected' : '',
        $prop->isStatic() ? ' static' : '',
        $prop->getName(),
        $prop->isDefault() ? 'declared at compile-time' : 'created at run-time',
        var_export(Reflection::getModifierNames($prop->getModifiers()),1)
);
$obj= new String();//Create an instance of String
printf("--->Value is: ");//Get current value
var_dump($prop->getValue($obj));
$prop->setValue($obj,10); // Change value
printf("---> Setting value to 10, new value is: ");
var_dump($prop->getValue($obj));
var_dump($obj); //Dump object
?>[/php]
注:试图获得或设置私有的或保护的类属性的值将导致一个被抛出的异常。
映射扩展(ReflectionExtension)
ReflectionExtension类允许你反向设计扩展。你可以在使用get_loaded_extensions()运行的时候重新返回所有加载的扩展。
[php]
<?php
class ReflectionExtension implements Reflector
{   final private __clone()
    public __construct(string name)
    public string __toString()
    public static string export()
    public string getName()
    public string getVersion()
    public ReflectionFunction[] getFunctions()
    public array getConstants()
    public array getINIEntries()
    public ReflectionClass[] getClasses()
    public array getClassNames()
}
?> [/php]
为了内省一个扩展,你必须首先创建ReflectionExtension类的一个实例。你可以随后访问这个实例的任何上述方法。
例子 19-38. 使用ReflectionExtension 的类
[php]
<?php
// Create an instance of the ReflectionProperty class
$ext=new ReflectionExtension('standard');
// Print out basic information
printf("Name        : %s/n" .
    "Version     : %s/n" .
    "Functions   : [%d] %s/n" .
    "Constants   : [%d] %s/n" .
    "INI entries : [%d] %s/n" .
    "Classes     : [%d] %s/n",
        $ext->getName(),
        $ext->getVersion()?$ext->getVersion():'NO_VERSION',
        sizeof($ext->getFunctions()),
        var_export($ext->getFunctions(),1),
        sizeof($ext->getConstants()),
        var_export($ext->getConstants(),1),
        sizeof($ext->getINIEntries()),
        var_export($ext->getINIEntries(),1),
        sizeof($ext->getClassNames()),
        var_export($ext->getClassNames(),1)
);
?>[/php]
扩展中的映射类(Extending the reflection classes)
万一你想创建一个构建类的专用的形式(就是说:在输出时创建彩色的HTML,拥有易访问的成员变量来代替方法或拥有公共方法),你可以继续和扩展它们。
例子 19-39. Extending the built-in classes
[php]
<?php
/**  My Reflection_Method class  */
class My_Reflection_Method extends ReflectionMethod
{   public $visibility = '';
    public function __construct($o, $m)
    {   parent::__construct($o, $m);
        $this->visibility= Reflection::getModifierNames($this->getModifiers());
    }
}
class T {  protected function x() { }  } //Demo class #1
class U extends T {  function x() { }  } //Demo class #2
var_dump(new My_Reflection_Method('U','x'));//Print out information
?>[/php]
注意警告:如果你重写构造函数,请记住在你插入任何代码之前通知父类的构造函数。不这样做将导致以下:致命错误: 内部错误:返回映射对象失败。

2006-5-4 19:19 forest
第19章 类与对象(PHP5)之十五:典型提示(线索)Type Hinting

PHP5引入了类型提示。函数现在能给对象强制参数(在函数原型中通过指定类的名字)或数组(从PHP 5.1开始) 。
例子 19-40. Type Hinting examples
[php]
<?php
class MyClass // An example class
{/**A test function
    * First parameter must be an object of type OtherClass */
    public function test(OtherClass $otherclass) { echo $otherclass->var; }
    /*Another test function  * First parameter must be an array*/
    public function test_array(array $input_array){  print_r($input_array); }
}
class OtherClass{  public $var='Hello World';  }//Another example class
?> [/php]
Failing to satisfy the type hint results in a fatal error.
[php]<?php
// An instance of each class
$myclass = new MyClass;
$otherclass = new OtherClass;
// Fatal Error: Argument 1 must be an object of class OtherClass
$myclass->test('hello');
// Fatal Error: Argument 1 must be an instance of OtherClass
$foo = new stdClass;
$myclass->test($foo);
$myclass->test(null); //Fatal Error: Argument 1 must not be null
$myclass->test($otherclass); //Works: Prints Hello World
$myclass->test_array('a string');//Fatal Error:Argument 1 must be an array
$myclass->test_array(array('a', 'b', 'c'));//Works: Prints the array
?>[/php]
Type hinting also works with functions:
类型提示也可以与函数协同工作。
[php]
<?php
class MyClass {  public $var = 'Hello World';  }//An example class
/**A test function * First parameter must be an object of type MyClass  */
function MyFunction(MyClass $foo){  echo $foo->var;  }
$myclass = new MyClass; //Works
MyFunction($myclass);
?>[/php]
类型提示可以只是对象和数组(从PHP 5.1开始)类型。传统的类型提示不支持整型和字符串型。

在此我把“Type Hinting”翻译为“类型提示”不知道合适不合适?
请大家提出建议,谢谢!!
 
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页