明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

Php5.0說明 ------為面向對象而生的php5

[摘要]Php5.0說明 ------為面向對象而生的php5 為面向對象而生的PHP5---------------------------------------------[摘要]目前開發(fā)中的...
Php5.0說明 ------為面向對象而生的php5
為面向對象而生的PHP5
---------------------------------------------



[摘要]目前開發(fā)中的PHP5,其面向對象的機能已經被大幅度的強化了。下一代的PHP將會是怎樣的一種語言呢?下面我們來詳細講解一下目前發(fā)布的PHP5的beta release。




(一) Zend 2.0的誕生
現(xiàn)在的PHP4所使用的基本文法是被稱之為Zend 引擎的腳本編譯引擎。這個就是PHP4的優(yōu)良機能的原因之一,是作為對PHP3的改進而生成的一種語言。大家一直認為,PHP4的性能根據(jù)當初的目標,比PHP3有了很大的提升,在網(wǎng)絡編程的世界里占據(jù)了很大的份額。

開發(fā)了Zend 引擎的Zend公司是在開發(fā)PHP4的同時,由PHP3的主要開發(fā)者Zeev Suraski和Andi Gutmans所創(chuàng)立的企業(yè)合并而來的。Zend的名稱是由Zeev和Andi的名字合起來組成的。Zend公司的商業(yè)模式是,持續(xù)不斷的為open source提供zend 引擎的PHP內核 (core),同時提升周邊產品開發(fā)和販賣的利益。以open source software作為基盤的商業(yè),在世界范圍內大多數(shù)正在苦戰(zhàn)的企業(yè)中,算是比較好的典型例子了。

■PHP4的局限

托PHP4成功的福,這個用途的適用范圍逐漸變廣起來。作為企業(yè)級的用途而使用PHP的說法時有所聞。因此,就有了這樣一個問題,構筑大規(guī)模網(wǎng)站的時候,代碼的再利用性十分差。具體來說就是,PHP4的面向對象性能很弱,因此習慣于使用Java等的技術人員對此有很多的抱怨。

逐步的改善PHP4的面向對象的性能,大幅度的更改基本文法,開發(fā)者達成了更新PHP記述方法的開拓目的。

■Zend 2.0開始開發(fā)
隨后,Zend公司PHP中心的開發(fā)者們在2001年7月發(fā)表了作為下一代PHP語言引擎的Zend 2.0引擎的構想。以[Zend Engine version 2.0: Feature Overview and Design]
(http://www.zend.com/engine2/ZendEngine-2.0.pdf)作為目標的同時,面向對象的性能大幅度的強化了。
目前的PHP4 Zend 引擎的擴張情況與昔日的PHP3如出一轍。這就意味著,要提升新的語言引擎的主版本號,明確方法目標,迎接來自開發(fā)團體的稱贊。

Ze2的開發(fā),與以往的Zend引擎一樣,都是運行在open source的模式下的。最新的源代碼在CVS上被全面的公開,因為是面向開放的開發(fā)者的,關于開發(fā)的議論非常的活躍。

現(xiàn)在Ze2被決定采用于PHP的下一個版本PHP5中。最終發(fā)布的時間現(xiàn)在還未定,但是假如根據(jù)Zend公司2003年4月1日發(fā)布的Newsletter的話,現(xiàn)在的應該就是Beta Release了。


(二) PHP5的新特性

接下來請按照順序看一下被強化的PHP5的性能。首先是最為重要的面向對象性能,類的實體特性在大幅度的被修改著。這里說的僅是關于類的新特性。

· 對象的參照過渡是默認的(default)
· 引入訪問屬性的限制
· 引入訪問方法的限制
· 抽象類和抽象方法
· 接口
· final聲明
· 名空間
· 類內常量
· 類變量
· 統(tǒng)一構建器
· 析構函數(shù)(Distructor)
· 其他附屬特性

以上內容是根據(jù)2003年4月22日CVS上登錄版本資料所寫的,在正式的發(fā)布之前,也有變動的可能性。

■對象的默認參照過渡

在PHP4中,在以變量$var1為類的實體對象的時候,如果$var2 = $var1;那么,在$var2中,$var1的復制被代入。明顯的,$var2為了指向與$var1相同的對象,就要寫成$var2 =& $var1,必須要加上&作為參照。
而在PHP5,對象的代入將成為自動的參照過渡。也就是說,
$var2=$var1,兩者指向相同的對象。如果想要同php4一樣,帶入copy,那么就會運用到導入__clone()的方法。
$var2 = $var1->__clone();此處,clone前面是兩個連續(xù)的“_”
(這僅僅是類的實體的特性)


■引入訪問屬性的限制

在PHP4的類中,連同屬性和方法在內,可以自由的訪問類的內外任何地方,而沒有限制。因此,用戶就無法防范屬性的無意中的更改。

而在PHP5中,同C++和Java一樣,導入了private, protected, public三個等級的訪問限制,使得類的設計者能夠對屬性和方法的使用方法進行限定。以下是各種訪問限制的意思。

· Public: 可以自由的在類的內外任何地方進行參照、變更
· Private: 只能在這個類的方法中進行參照、變更
· Protected:能夠在這個類以及繼承了這個類的另一個類的方法中進行參照、變更。另外,在繼承的類中,能夠寫入訪問指定。

在PHP4中的“var”,同以往一樣與public有著相同的意思。下面就來舉一個例子,讓我們來看看訪問限制是怎樣起作用的。

PHP代碼:--------------------------------------------------------------------------------
class Hoge1 {
 private $var1 = 'A';
 protected $var2 = 'B';
 protected $var3 = 'C';

 function setLower() {
  $this->var1 = 'a';
  $this->var2 = 'b';
  $this->var3 = 'c';
 }
 function var1() {
  return $this->var1;
 }
 function var2() {
  return $this->var2;
 }
 function var3() {
  return $this->var3;
 }
}

--------------------------------------------------------------------------------

在這個類中,帶有$var1, $var2, $var3三個屬性。$var1被聲明為private, $var2和$var3是protected.在此處

PHP代碼:--------------------------------------------------------------------------------
$hoge=new Hoge1;
echo’var1:’.$hoge->var1.”
n”

--------------------------------------------------------------------------------

如果嘗試參照不允許從外部進行訪問的private屬性,那么就會出現(xiàn)如下錯誤:

Fatal error: Cannot access private property hoge1::$var1 in /path/to/script.php on line XX

對于protected的$var2也是相同的。

但是,因為$hoge的方法是沒有private和protected的,所以下面的代碼能夠正常運作,返回內部私有和保護變量的值。

PHP代碼:--------------------------------------------------------------------------------
echo 'var1: ' . $hoge->var1() . "
\n"; // var1: A
echo 'var2: ' . $hoge->var2() . "
\n"; // var2: B
echo 'var3: ' . $hoge->var3() . "
\n"; // var3: C

$hoge->setLower();

echo 'var1: ' . $hoge->var1() . "
\n"; // var1: a
echo 'var2: ' . $hoge->var2() . "
\n"; // var2: b
echo 'var3: ' . $hoge->var3() . "
\n"; // var3: c

--------------------------------------------------------------------------------

其次,為了能夠看到protected的屬性的狀態(tài),我們試著創(chuàng)造了繼承了Hoge1的類Hoge2

PHP代碼:--------------------------------------------------------------------------------
class Hoge2 extends Hoge1 {
 public $var3 = '3';

 function d_var1() {
  return $this->var1;
 }
 function d_var2() {
  return $this->var2;
 }
 function d_var3() {
  return $this->var3;
 }
}

--------------------------------------------------------------------------------

在類Hoge2中,只有$var3被聲明為public。在屬性是protected的情況下,從子類進行訪問有何種限制,是由子類的屬性聲明決定的。在Hoge2中,因為$var3被聲明是public,因此無論是從何處都可以訪問Hoge2的$var3(實體是Hoge1的$var3)。因為$var1在Hoge1中是private,因此,在Hoge2子類中Hoge1的$var1不會被繼承,而在Hoge2中有可能會做出名為$var1的屬性,因此,必須要明確區(qū)分Hoge1::$var1和Hoge2::$var1。

PHP代碼:--------------------------------------------------------------------------------
$hoge = new Hoge2;

echo 'var1: ' . $hoge->var1 . "
\n";   // var1:
// echo 'var2: ' . $hoge->var2 . "
\n";  // Error
echo 'var3: ' . $hoge->var3 . "
\n";   // var3: 3

echo 'var1: ' . $hoge->d_var1() . "
\n"; // var1:
echo 'var2: ' . $hoge->d_var2() . "
\n"; // var2: B
echo 'var3: ' . $hoge->d_var3() . "
\n"; // var3: 3

--------------------------------------------------------------------------------


$hoge->var1是與Hoge1::var1沒有關系的變量,因此不會有任何顯示,因為var2有protected訪問限制,所以如果不通過method就直接參照$var2,就會出現(xiàn)致命錯誤。

■引入訪問方法的限制

與上述相同,此處也分為private, protected, public三種。

· Public: 能夠從任何地方調用
· Private: 只能夠從這個類的method內調用
· Protected: 只能夠從這個類以及subclass的method中調用

此處的意思同Java和C++相同,請不要搞混。

■抽象(abstract)的類和抽象的方法

支持與Java相同的抽象類和抽象方法。抽象方法只提供了方法名的調用方式,而沒有提供實體。另外,持有抽象方法的類,必須抽象宣言類本身。如果想要直接作成抽象類的對象,那么就會出現(xiàn)如下的致命錯誤。

Fatal error: Cannot instantiate abstract class ClassName

產生錯誤的實際的例子如下所示:

PHP代碼:--------------------------------------------------------------------------------



abstract class MyAbstract {
 abstract public function test();
 public function test2() {
  echo "MyAbstract::test2() called.
\n";
 }
}

class MyImplement extends MyAbstract {
 public function test() {
  echo "MyImplement::test() called.
\n";
 }
}

$obj = new MyImplement;
$obj->test();

?>

--------------------------------------------------------------------------------


■接口(interface)

支持與Java相同的接口(interface)。接口是適合所描述的外部調用形式而設計組合起來的。
接口的實體不能夠記錄。相反的,實現(xiàn)接口的類必須持有與這個接口的方法相對應的實體。另外,類能夠實現(xiàn)多個接口,因此,有可能實現(xiàn)多重繼承。

PHP代碼:--------------------------------------------------------------------------------


interface Throwable {
 public function getMessage();
}

interface Serializable {
 public function toString();
}

class MyException implements Throwable, Serializable {
 public function getMessage() {
  return 'this is MyException message';
 }

 public function toString() {
  return 'MyException: this is MyException message';
 }
}

$e = new MyException;
echo $e->getMessage();
echo $e->toString();
?>

--------------------------------------------------------------------------------


■final聲明

同Java一樣,PHP5支持final聲明。如果對于一個方法追加final聲明,這個方法將肯定在子類不能重載(Override)。如果方法被final聲明了,但是還在子類中重載,就會出現(xiàn)如下錯誤:

PHP代碼:--------------------------------------------------------------------------------
Fatal error: Cannot override final method fuga::foo()

--------------------------------------------------------------------------------


產生錯誤的例子:

PHP代碼:--------------------------------------------------------------------------------

class Fuga {
 final function foo() {
  echo "this is final function\n";
 }
}

class Hoge extends Fuga {
 function foo() {
  echo "this is not final function\n";
 }
}
?>

--------------------------------------------------------------------------------


(三) PHP5的新特性(續(xù))

PHP5的發(fā)布計劃

在前面的文章中我們提到,“根據(jù)ZEND公司2003年4月1日發(fā)布的訊息的話,現(xiàn)在的應該就是Beta Release了”,但是開發(fā)者內部討論的結果是,Beta為時尚早,而且有可能不是Beta Release.

對這方面動向有興趣的可以參照 news://news.php.net/ 上所公布的信息 php.version5.dev:372

在這個文件中,PHP5的發(fā)布計劃又重新回到了一張白紙,而另一方面,Zend Engine2的開發(fā)正在著手進行中。PHP5的Release其實大體就是盼望著“快點到年終吧”。

PHP5的新特性

接著我們來看一下在前面所講到的其他一些關于類的新增的機能

■名空間

PHP5支持名空間。因此,我們可以在名空間內裝入類、變量、常量、函數(shù)。

在PHP4的Scope中,只有global、函數(shù)內、類內這三個種類,所以要特別注意如果不注意的話,將會很容易“污染”global空間。假如使用名空間的話我們就能夠在package里分離變量命名空間,因此應該就能比較容易的做成獨立的package。

使用實例如下:

PHP代碼:--------------------------------------------------------------------------------
namespace This {
 class Hoge {
 }
 const aConstant = 'This Constant';
 function aFunction() {}
 var $aVariable = 'This Variable';
}

$obj = new This::Hoge;
echo This::aConstant . "
\n";
This::aFunction();
echo This::$aVariable . "
\n";

--------------------------------------------------------------------------------


假設要訪問名空間內的對象的話,就應該這樣做:

名空間名::對象名

但是PHP5的名空間不會套入與C++相異的樣子。

■Class內常量

使用關鍵字const,能夠在類、名空間內定義常量。這里因為是常量,因此一定要在常量名的前面加上$。Class內的常量,比這個類中的global常量的優(yōu)先級要高。

在這里const是預約語,因此在class名和函數(shù)名中使用const的時候要做必要的修正。

PHP代碼:--------------------------------------------------------------------------------


define('constant_value', 'global constant');

class MyClass {
 const constant_value = 'class constant';

 function printConstant() {
  print constant_value;
 }
}

echo MyClass::constant_value . "
\n";
MyClass:rintConstant();
?>

--------------------------------------------------------------------------------


在這個例子里,MyClass:rintConstant()是顯示常量constant_value的值,但是,constant_value存在于global空間和Class內這兩個地方。在這種情況下,MyClass內的常量constant_value的優(yōu)先級較高,被顯示為「class constant」。

■對象變量

即使是在類沒有被實例化狀態(tài)下,對象變量也能準確的按照指定的值被初始化。訪問的方法如下:

類名::$變量名

PHP代碼:--------------------------------------------------------------------------------


class Hoge {
 static $my_static = 5;
}

print Hoge::$my_static;
?>

--------------------------------------------------------------------------------


■統(tǒng)一構建器

在生成對象的時候,能夠自動被調用的方法被稱作“構建器”。

PHP4中的構建器,是與Class名相同的方法名。這是與Java和C++相同的地方,因此,對于一些用慣了的人來說,不會有別扭感。但是,如果要從子類中調用父類的構建器的話,在PHP中就必須特意寫上父類的名字。

在PHP中,父類的構建器不能被自動調用,因此,情況就比較多。
在PHP5中,統(tǒng)一采用了__constructor這個構建器名稱,不管class名是什么,凡是被稱為__construct()的,都被當作構建器來處理。

另外,考慮到同PHP4的互換性,假如存在于Class名相同的以前的構建器名,那么,優(yōu)先使用那個構建器。

PHP代碼:--------------------------------------------------------------------------------


class BaseClass {
 function __construct() {
  print "In BaseClass constructor\n";
 }
}

class SubClass extends BaseClass {
 function __construct() {
  parent::__construct();
  print "In SubClass constructor\n";
 }
}

$obj = new BaseClass();
$obj = new SubClass();
?>

--------------------------------------------------------------------------------


■析構函數(shù)

與構建器相反,能夠在對象釋放時自動被調用的方法被稱為析構函數(shù)。

PHP4支持析構函數(shù),通過登錄在PHP運行終止時用register_shutdown_function()調用的函數(shù),只有類似的實行方法。PHP5正式支持析構函數(shù),能夠在類中指定對象釋放時的動作。

析構函數(shù)就是名為__destruct的方法。當對象內部的參照計數(shù)器變成0的時候,__destruct()被調用,然后對象所使用的內存被釋放出來。

PHP代碼:--------------------------------------------------------------------------------


class MyDestructableClass {
 function __construct() {
  print "In constructor\n";
  $this->name = 'MyDestructableClass';
 }

 function __destruct() {
  print 'Destroying ' . $this->name . "\n";
 }
}

$obj = new MyDestructableClass();
?>

--------------------------------------------------------------------------------


另外,與構建器相同的地方是,父類的析構函數(shù)不能被自動的調用,必要的時候,需要用命令:

parent::__destruct();

■訪問

在PHP4中,如果訪問了一個不存在的屬性,那么系統(tǒng)就會自動生成與之相對應的新屬性。

PHP代碼:--------------------------------------------------------------------------------
class Hoge {
}

$obj = new Hoge;
$obj->prop = "This is new property";

--------------------------------------------------------------------------------



如上所示,當把值代入一個不存在的屬性時,那個代入點就會自動生成一個新屬性。同樣的,訪問一個不存在的屬性,就如同被代入NULL值的變量一樣,不會發(fā)生錯誤。

在PHP5中追加了一點,就是能夠對訪問任意的屬性進行控制。在類中如果存在__set()、__get()這樣的方法,替代上述的動作此處的方法將能夠被調用。例如:

PHP代碼:--------------------------------------------------------------------------------


class Hoge {
 function __set($name, $value) {
  print "__set() is called with ($name, $value)\n";
  $this->$name = $value;
 }
}

$obj = new Hoge;

$obj->a = '123';
$obj->a = '456';
$obj->b = '789';
?>

--------------------------------------------------------------------------------


在這里,__set 方法被作為未定義屬性的代入方法,在顯示值之后將值代入未定義屬性。

PHP代碼:--------------------------------------------------------------------------------
$obj->a = '123';

--------------------------------------------------------------------------------


執(zhí)行這一句時,因為在這個時候不存在屬性a,因此,作為代替,__set 方法被調用。

__set() is called with (a, 123)

其次,

$obj->a = '456';

再一次的代入$obj->a,這一次,由于屬性a已經存在,所以__set 沒有被調用,和通常一樣把值代入到了屬性a中去了。

$obj->b = '789';

這一回,我們把值代入另一個屬性b中,同a的第一次情況一樣,

__set() is called with (b, 789)

同__set 方法相反,__get 方法是在對不存在的屬性的引用時調用的。將這兩者結合起來,再來看一下對于屬性的訪問,實際上,利用它能夠寫出在不同的場合都能做出不同響應的類來。

PHP代碼:--------------------------------------------------------------------------------


class Hoge {
 public $properties;

 function __set($name, $value) {
  $this->properties[$name] = $value;
 }
 function __get($name) {
  return $this->properties[$name];
 }
}

$obj = new Hoge;

$obj->a = '123';
$obj->b = '456';
echo $obj->a;
echo $obj->b;

print_r($obj);
?>

--------------------------------------------------------------------------------


在這個例子里,對類中所有屬性的訪問被裝入了$properties中,這樣,使我們加入的屬性不直接的附在對象之下。這是個不太能容易理解的例子,例如,試著把這個例子中的保存到$properties改成存入文件或是數(shù)據(jù)庫會很有趣吧。實際上,在對象里面,我們能夠簡單的實現(xiàn)讓許多的復雜的操作。

與__set, __get多少有些不同,但是__call也能用來書寫不存在的方法,當我們向如下例子一樣調用對象的方法的時候,

$object->methodname();

如果這個類中不存在methodname這個方法,通常情況下,就會出現(xiàn)如下錯誤:

Fatal error: Call to undefined method Class::methodname()

但是,如果這個類中存在__call這個方法,作為替代,__call就被調用。__call的參數(shù)有兩個,第一個參數(shù)是被叫出的方法名,第二個參數(shù)是保持了的被調用的參數(shù)的數(shù)組?紤]到有很多的使用方法,除了以下的例子外,還可以使用其它的方法。

PHP代碼:--------------------------------------------------------------------------------


class Proxy {
 private $object;

 function __call($name, $params) {
  if (isset($this->object)) {
   if (method_exists($this->object, $name)) {
   return call_user_func_array(array($this->object, $name), $params);
   }
   else {
   return "method not exists.";
   }
  }
 }
 function __construct($object) {
  $this->object = $object;
 }
}

class Hoge {
 function add($var1, $var2) {
  return $var1 + $var2;
 }
}

$p = new Proxy(new Hoge);

$result = $p->add(1, 2);
echo "result: $result
\n";

$result = $p->sub(5, 3);
echo "result: $result
\n";
?>



全新的對象模型
PHP中的對象處理部分已完全重寫,具有更佳的性能和更多的功能。在PHP的以前版本中,對象與內建變量類型(如integer和string)的處理方法相同,其弊端是當變量被賦值為對象或對象作為參數(shù)傳遞時,得到的是對象復制品。而在新版本中,對象通過句柄進行引用,而不是通過它的值。(句柄可以認是為是對象的標識符)
很多PHP程序員可能未意識到以前的對象模型的“復制怪癖”,因此以前的PHP程序將不需要做任何更改,或只做很小的改動即可運行
私有和保護成員
PHP 5引入了私有和保護成員變量,它們可以定義類屬性在何時可以被訪問。

類的保護成員變量能在該類的擴展類中被訪問,而私有成員變量只能在本類中被訪問。
class MyClass {
private $Hello = "Hello, World!\n";
protected $Bar = "Hello, Foo!\n";
protected $Foo = "Hello, Bar!\n";

function printHello() {
print "MyClass::printHello() " . $this->Hello;
print "MyClass::printHello() " . $this->Bar;
print "MyClass::printHello() " . $this->Foo;
}
}

class MyClass2 extends MyClass {
protected $Foo;

function printHello() {
MyClass::printHello(); /* Should print */
print "MyClass2::printHello() " . $this->Hello; /* Shouldn't print out anything */
print "MyClass2::printHello() " . $this->Bar; /* Shouldn't print (not declared)*/
print "MyClass2::printHello() " . $this->Foo; /* Should print */
}
}

$obj = new MyClass();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello(); /* Should print */

$obj = new MyClass2();
print $obj->Hello; /* Shouldn't print out anything */
print $obj->Bar; /* Shouldn't print out anything */
print $obj->Foo; /* Shouldn't print out anything */
$obj->printHello();
?>

私有和保護方法
在PHP 5(ZEND引擎2)中,還引入了私有和保護方法。
例:
class Foo {
private function aPrivateMethod() {
echo "Foo::aPrivateMethod() called.\n";
}

protected function aProtectedMethod() {
echo "Foo::aProtectedMethod() called.\n";
$this->aPrivateMethod();
}
}

class Bar extends Foo {
public function aPublicMethod() {
echo "Bar::aPublicMethod() called.\n";
$this->aProtectedMethod();
}
}

$o = new Bar;
$o->aPublicMethod();
?>
以前代碼中的用戶自定義類或方法中雖未定義"public," "protected" 或 "private"等關鍵字,但無需編輯即可運行。
抽象類和方法
PHP 5還引入了抽象類和方法。抽象方法只聲明方法定義, 不供實際運行。包含抽象方法的類需要聲明為抽象類。
例:
abstract class AbstractClass {
abstract public function test();
}

class ImplementedClass extends AbstractClass {
public function test() {
echo "ImplementedClass::test() called.\n";
}
}

$o = new ImplementedClass;
$o->test();
?>
抽象類不能實例化。以前代碼中的用戶自定義類或方法中雖未定義"abstract”關鍵字,但無需編輯即可運行。
接口
ZEND引擎2.0引入了接口。一個類可以運行任意的接口列表。
Example
例:
interface Throwable {
public function getMessage();
}

class Exception implements Throwable {
public function getMessage() {
// ...
}
?>
以前代碼中的用戶自定義類或方法中雖未定義"interface”關鍵字,但無需編輯即可運行。
類類型定義
在保留類無需定義類型的同時,PHP 5引入了類類型定義來聲明希望把哪個類通過參數(shù)傳遞給一個方法。
Example
例:
interface Foo {
function a(Foo $foo);
}

interface Bar {
function b(Bar $bar);
}

class FooBar implements Foo, Bar {
function a(Foo $foo) {
// ...
}

function b(Bar $bar) {
// ...
}
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>
這些類類型定義在不象一些需要類型預定義的語言在編譯中進行檢查,而是在運行時進行。這意味著:
function foo(ClassName $object) {
// ...
}
?>
等價于:
function foo($object) {
if (!($object instanceof ClassName)) {
die("Argument 1 must be an instance of ClassName");
}
}
?>
本語法只用于對象或類,不適用于內建類型。
final
PHP 5引入了“final”關鍵字定義在子類中不能被覆蓋的成員或方法。
例:
class Foo {
final function bar() {
// ...
}
}
?>
以前代碼中的用戶自定義類或方法中雖未定義"final"關鍵字,但無需編輯即可運行。
對象克隆
PHP 4在對象被復制時,用戶不能決定拷貝的機制。在復制時,PHP 4只一位一位地復制一個和原來對象一模一樣的復制品。
我們并不是每次都要建立一個完全一樣的復制品。一個很好的需要一種復制機制的例子是,當有一個代表一個GTK窗口的對象,它擁有該窗口的所有資源,當你建立一個拷貝時,你可能需要一個新的窗口,它擁有原窗口的所有屬性,但需要擁有新窗口的資源。另外一個例子是你有一個對象引用了另外一個對象,當你復制父對象時,你希望建立那個引用對象的新實例,以使復制品引用它。
對一個對象的拷貝通過調用對象的__clone()方法完成:
$copy_of_object = $object->__clone();
?>
當開發(fā)者請求建立一個對象的新的拷貝時,ZEND引擎會檢查是否定義了__clone()方法。如果未定義的話,它會調用一個默認的__clone()方法來復制該對象的所有屬性。如果定義了該方法,該方法會負責在拷貝中設置必要的屬性。為方便起見,引擎會提供一個函數(shù)從源對象中導入所有的屬性,這樣它就可以先得到一個具有值的源對象拷貝,只需要對需要改變的屬性進行覆蓋即可。
例:
class MyCloneable {
static $id = 0;

function MyCloneable() {
$this->id = self::$id++;
}

function __clone() {
$this->name = $that->name;
$this->address = "New York";
$this->id = self::$id++;
}
}

$obj = new MyCloneable();

$obj->name = "Hello";
$obj->address = "Tel-Aviv";

print $obj->id . "\n";

$obj = $obj->__clone();

print $obj->id . "\n";
print $obj->name . "\n";
print $obj->address . "\n";
?>
統(tǒng)一的構造方法名
ZEND引擎允許開發(fā)者定義類的構造方法。具有構造方法的類在新建時會首先調用構造方法,構造方法適用于在正式使用該類前進行的初始化。
在PHP4中,構造方法的名稱與類名相同。由于在派生類中調用父類的作法比較普遍,因此導致在PHP4中當類在一個大型的類繼承中進行移動時,處理方式有點笨拙。當一個派生類被移動到一個不同的父類中時,父類的構造方法名必然是不同的,這樣的話派生類中的有關調用父類構造方法的語句需要改寫。
PHP 5 introduces a standard way of declaring constructor methods by calling them by the name __construct().
PHP5引入了方法名__construct()來定義構造方法。
Example
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}

class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>
為向下兼容,PHP5當在類不能找到__construct()方法時,會通過老的方法也就是類名來查找構造方法。這意味著唯一可能產生兼容性問題的是在以前的代碼中已經使用了一個名為__construct()的方法名。

析構方法
定義析構方法是十分有用的。析構方法可以記錄調試信息,關閉數(shù)據(jù)庫連接,還有做其它的掃尾工作。PHP4中并無此機制,盡管PHP已支持注冊在請求結束時需要運行的函數(shù)。
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as Java: When the last reference to an object is destroyed the object's destructor, which is a class method name %__destruct()% that recieves no parameters, is called before the object is freed from memory.
PHP5引入了與其它面向對象語言如Java語言相似的析構方法:當最后一個該對象的引用被清除時,系統(tǒng)將會在該對象從內存中釋放前調用名為__destruct()的析構方法。
例:
class MyDestructableClass {
function __construct() {
print "In constructor\n";
$this->name = "MyDestructableClass";
}

function __destruct() {
print "Destroying " . $this->name . "\n";
}
}

$obj = new MyDestructableClass();
?>
和構造方法相似,引擎將不調用父類的析構方法,為調用該方法,你需要在子類的析構方法中通過parent::__destruct()語句進行調用。
常量
PHP 5 引入了類常量定義:
class Foo {
const constant = "constant";
}

echo "Foo::constant = " . Foo::constant . "\n";
?>

PHP5允許常量中有表達式,但在編譯時常量中的表達式將被計算.,因此常量不能在運行中改變它的值。
class Bar {
const a = 1<<0;
const b = 1<<1;
const c = a b;
}
?>
以前代碼中的用戶自定義類或方法中雖未定義"const”關鍵字,但無需編輯即可運行。
例外
PHP 4 had no exception handling. PHP 5 introduces a exception model similar to that of other programming languages.
PHP4中無例外處理,PHP5引用了與其它語言相似的例外處理模型。
例:
class MyExceptionFoo extends Exception {
function __construct($exception) {
parent::__construct($exception);
}
}

try {
throw new MyExceptionFoo("Hello");
} catch (MyException $exception) {
print $exception->getMessage();
}
?>
以前代碼中的用戶自定義類或方法中雖未定義'catch', 'throw' 和 'try'關鍵字,但無需編輯即可運行。
函數(shù)返回對象值
In PHP 4 it wasn't possible to dereference objects returned by functions and make further method calls on those objects. With the advent of Zend Engine 2, the following is now possible:
在PHP4中,函數(shù)不可能返回對象的值并對返回的對象進行方法調用,通過ZEND引擎2中,這一切變得可能:
class Circle {
function draw() {
print "Circle\n";
}
}

class Square {
function draw() {
print "Square\n";
}
}

function ShapeFactoryMethod($shape) {
switch ($shape) {
case "Circle":
return new Circle();
case "Square":
return new Square();
}
}

ShapeFactoryMethod("Circle")->draw();
ShapeFactoryMethod("Square")->draw();
?>
靜態(tài)類中的靜態(tài)成員變量現(xiàn)在可初始化
Example
class foo {
static $my_static = 5;
}

print foo::$my_static;
?>
靜態(tài)方法
PHP5引入了關鍵字'static'來定義一個靜態(tài)方法,這樣可以從對象外進行調用。
例:
class Foo {
public static function aStaticMethod() {
// ...
}
}

Foo::aStaticMethod();
?>
虛擬變量$this在靜態(tài)方法中無效。
instanceof
PHP5引入了關鍵字instanceof來確定一個對象是否是某一個對象的實例,或某一個對象的派生,或使用了某一個接口。
例:
class baseClass { }

$a = new baseClass;

if ($a instanceof basicClass) {
echo "Hello World";
}
?>
靜態(tài)函數(shù)變量
所有的靜態(tài)變量現(xiàn)在在編譯時進行處理,這允許開發(fā)者通過引用來指定靜態(tài)變量。這個變化提高了效率但意味著不可能對靜態(tài)變量進行間接引用。
函數(shù)中通過按地址傳送方式的參數(shù)允許定義默認值
例:
function my_function(&$var = null) {
if ($var === null) {
die("$var needs to have a value");
}
}
?>
__autoload()
在初始化一個未定義的類時,引擎將自動調用__autoload()攔截器函數(shù)。該類名將作為__autoload()攔截器函數(shù)唯一參數(shù)傳遞給它。
例:
function __autoload($className) {
include_once $className . ".php";
}

$object = new ClassName;
?>
方法和屬性調用的重載
通用 __call(), __get() 和 __set()方法可以進行方法和屬性調用的重載。

例: __get() 和 __set()
class Setter {
public $n;
public $x = array("a" => 1, "b" => 2, "c" => 3);

function __get($nm) {
print "Getting [$nm]\n";

if (isset($this->x[$nm])) {
$r = $this->x[$nm];
print "Returning: $r\n";
return $r;
} else {
print "Nothing!\n";
}
}

function __set($nm, $val) {
print "Setting [$nm] to $val\n";

if (isset($this->x[$nm])) {
$this->x[$nm] = $val;
print "OK!\n";
} else {
print "Not OK!\n";
}
}
}

$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>
例: __call()
class Caller {
var $x = array(1, 2, 3);

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);
?>