天天看點

類與對象(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

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

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 {    // ...}

class Counter extends Object implements Serializable

{   const START = 0;

    private static $c = Counter::START;

    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;

        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

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

{

    public function test(OtherClass $otherclass) { echo $otherclass->var; }

    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

function MyFunction(MyClass $foo){  echo $foo->var;  }

$myclass = new MyClass; //Works

MyFunction($myclass);

?>[/php]

類型提示可以隻是對象和數組(從PHP 5.1開始)類型。傳統的類型提示不支援整型和字元串型。

在此我把“Type Hinting”翻譯為“類型提示”不知道合适不合适?

請大家提出建議,謝謝!!