PHP 5/Zend Engine 2.0的改進
Warton譯 2003-09-12重慶<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
近兩年沒有使用PHP寫過程序了,今天要用PHP,就在網上查了查,看到了PHP5,一時之間興趣又大了起來,於是翻譯了這篇文章。
文章來源於http://www.php.net/。
新的對象模型
PHP中的對象處理部分已完全重寫,具有更佳的性能和更多的功能。在先前的PHP版本中,對象被當做原始的簡單類型
(如integer和string)來處理,這種方法的缺點是當變量被賦值或作爲參數傳遞時,得到的是對象拷貝。而在新版本中,
對象是通過句柄來引用的,而不是通過對象的值(句柄想象爲對象的標識符)。
很多PHP程序員可能未意識到老的對象模型的“copying quirks“,因此以前的大多數PHP程序將不需要做任何更改
即可運行,或只做很少的改動。
私有和保護成員
PHP 5引進了私有和保護成員變量,它們可以定義可視化的類屬性。
示例
保護成員變量能在該類的子類中被訪問,而私有成員變量只能在所屬類中被訪問。
<?php
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; /* 不輸出任何內容,以下類同 */
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)中,私有方法和保護方法也被引入。
示例:
<?php
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”。
例如:
<?php
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”關鍵字,但無需修改就可以運行。
接口(Interfaces)
ZEND引擎2.0引入了接口。一個類可以實現任意的接口列表。
例如:
<?php
interface Throwable {
public function getMessage();
}
class Exception implements Throwable {
public function getMessage() {
// ...
}
?>
舊的代碼中的用戶定義類或方法中雖然沒有定義"interface”關鍵字,但無需修改就可以正常運行。
類類型提示(Class Type Hints)
在保留類無需定義類型的同時,PHP 5引入了類類型提示來聲明,以期望把對象的類通過參數傳遞給一個方法。
例如:
<?php
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);
?>
這些類類型提示不是象一些需要類型定義的語言那樣在編譯中進行檢查,而是在運行時進行檢查。這就意味着:
<?php
function foo(ClassName $object) {
// ...
}
?>
is equivalent to:
<?php
function foo($object) {
if (!($object instanceof ClassName)) {
die("Argument 1 must be an instance of ClassName");
}
}
?>
這種語法只用於對象或類,不適用於內建(built-in)類型。
Final關鍵字(final)
PHP 5引入了“final”關鍵字以定義在子類中不能被覆蓋的成員或方法。
例:
<?php
class Foo {
final function bar() {
// ...
}
}
?>
以前所寫代碼中的用戶自定義類或方法中雖未定義"final"關鍵字,但無需修改就可以運行了。
對象克隆(Object Cloning)
PHP 4在對象被複制時,用戶不能判斷運行那個拷貝構造函數。在複製時,PHP 4根據對象的屬性
一位一位地複製一個同樣的複製品。
每次都要建立一個完全一樣的複製品並不總是我們想要的。一個很好的複製構造例子是,當有
一個代表一個GTK窗口的對象,它擁有該窗口的所有資源,當你建立一個拷貝時,你可能需要一
個新的窗口,它擁有原窗口的所有屬性,但需要擁有新窗口的資源。另外一個例子是你有一個
對象引用了另外一個對象,當你複製父對象時,你希望建立那個引用對象的新實例,以使複製品有一個單獨的拷貝。
對一個對象的拷貝通過調用對象的__clone()方法完成:
<?php$copy_of_object = $object->__clone();
?>
當開發者請求建立一個對象的新的拷貝時,ZEND引擎會檢查是否已經定義了__clone()方法。如果未定義
的話,它會調用一個默認的__clone()方法來複制該對象的所有屬性。如果定義了該方法,該方法會負責
在拷貝中設置必要的屬性。爲使用方便,引擎會提供一個函數從源對象中導入所有的屬性,這樣它就可
以先得到一個具有值的源對象拷貝,然後只需要對需要改變的屬性進行覆蓋即可。
ZEND引擎允許開發者定義類的構造方法。具有構造方法的類在新建時會首先調用構造方法,構造
方法適用於在正式使用該類前進行的初始化。
在PHP4中,構造方法的名稱與類名相同。由於在派生類中調用父類的作法比較普遍,因此導致在
PHP4中當類在一個大型的類繼承中進行移動時,處理方式有點笨拙。當一個派生類被移動到一個不同
的父類中時,父類的構造方法名必然是不同的,這樣的話派生類中的有關調用父類構造方法的語句需要改寫。
PHP5引入了一個定義構造方法的標準方式,通過調用它們的__construct()來定義。
<?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();
?>
定義析構方法是十分有用的。析構方法可以記錄調試信息,關閉數據庫連接,還有做其它的掃尾
工作。PHP4中並無此機制,儘管PHP已支持註冊在請求結束時需要運行的函數。
PHP5引入了與其它面嚮對象語言如Java語言相似的析構方法:當最後一個該對象的引用被清除時,
系統將會在該對象從內存中釋放前調用名爲__destruct()的析構方法。
<?php
class MyDestructableClass {
function __construct() {
print "In constructor/n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "Destroying " . $this->name . "/n";
}
}
$obj = new MyDestructableClass();
?>
和構造方法相似,引擎將不調用父類的析構方法,爲調用該方法,你需要在子
類的析構方法中通過parent::__destruct()語句進行調用。
per-class constants
<?php
class Foo {
const constant = "constant";
}
echo "Foo::constant = " . Foo::constant . "/n";
?>