為面向對象而生的PHP5
2024-05-04 22:53:46
供稿:網友
摘要]目前開發中的php5,其面向對象的機能已經被大幅度的強化了。下一代的php將會是怎樣的一種語言呢?下面我們來詳細講解一下目前發布的php5的beta release。
(一) zend 2.0的誕生
現在的php4所使用的基本文法是被稱之為zend 引擎的腳本編譯引擎。這個就是php4的優良機能的原因之一,是作為對php3的改進而生成的一種語言。大家一直認為,php4的性能根據當初的目標,比php3有了很大的提升,在網絡編程的世界里占據了很大的份額。
開發了zend 引擎的zend公司是在開發php4的同時,由php3的主要開發者zeev suraski和andi gutmans所創立的企業合并而來的。zend的名稱是由zeev和andi的名字合起來組成的。zend公司的商業模式是,持續不斷的為open source提供zend 引擎的php內核 (core),同時提升周邊產品開發和販賣的利益。以open source software作為基盤的商業,在世界范圍內大多數正在苦戰的企業中,算是比較好的典型例子了。
■php4的局限
托php4成功的福,這個用途的適用范圍逐漸變廣起來。作為企業級的用途而使用php的說法時有所聞。因此,就有了這樣一個問題,構筑大規模網站的時候,代碼的再利用性十分差。具體來說就是,php4的面向對象性能很弱,因此習慣于使用java等的技術人員對此有很多的抱怨。
逐步的改善php4的面向對象的性能,大幅度的更改基本文法,開發者達成了更新php記述方法的開拓目的。
■zend 2.0開始開發
隨后,zend公司php中心的開發者們在2001年7月發表了作為下一代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如出一轍。這就意味著,要提升新的語言引擎的主版本號,明確方法目標,迎接來自開發團體的稱贊。
ze2的開發,與以往的zend引擎一樣,都是運行在open source的模式下的。最新的源代碼在cvs上被全面的公開,因為是面向開放的開發者的,關于開發的議論非常的活躍。
現在ze2被決定采用于php的下一個版本php5中。最終發布的時間現在還未定,但是假如根據zend公司2003年4月1日發布的newsletter的話,現在的應該就是beta release了。
(二) php5的新特性
接下來請按照順序看一下被強化的php5的性能。首先是最為重要的面向對象性能,類的實體特性在大幅度的被修改著。這里說的僅是關于類的新特性。
· 對象的參照過渡是默認的(default)
· 引入訪問屬性的限制
· 引入訪問方法的限制
· 抽象類和抽象方法
· 接口
· final聲明
· 名空間
· 類內常量
· 類變量
· 統一構建器
· 析構函數(distructor)
· 其他附屬特性
以上內容是根據2003年4月22日cvs上登錄版本資料所寫的,在正式的發布之前,也有變動的可能性。
■對象的默認參照過渡
在php4中,在以變量$var1為類的實體對象的時候,如果$var2 = $var1;那么,在$var2中,$var1的復制被代入。明顯的,$var2為了指向與$var1相同的對象,就要寫成$var2 =& $var1,必須要加上&作為參照。
而在php5,對象的代入將成為自動的參照過渡。也就是說,
$var2=$var1,兩者指向相同的對象。如果想要同php4一樣,帶入copy,那么就會運用到導入__clone()的方法。
$var2 = $var1->__clone();此處,clone前面是兩個連續的“_”
(這僅僅是類的實體的特性)
■引入訪問屬性的限制
在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屬性,那么就會出現如下錯誤:
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的屬性的狀態,我們試著創造了繼承了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的屬性,因此,必須要明確區分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,就會出現致命錯誤。
■引入訪問方法的限制
與上述相同,此處也分為private, protected, public三種。
· public: 能夠從任何地方調用
· private: 只能夠從這個類的method內調用
· protected: 只能夠從這個類以及subclass的method中調用
此處的意思同java和c++相同,請不要搞混。
■抽象(abstract)的類和抽象的方法
支持與java相同的抽象類和抽象方法。抽象方法只提供了方法名的調用方式,而沒有提供實體。另外,持有抽象方法的類,必須抽象宣言類本身。如果想要直接作成抽象類的對象,那么就會出現如下的致命錯誤。
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)。接口是適合所描述的外部調用形式而設計組合起來的。
接口的實體不能夠記錄。相反的,實現接口的類必須持有與這個接口的方法相對應的實體。另外,類能夠實現多個接口,因此,有可能實現多重繼承。
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聲明了,但是還在子類中重載,就會出現如下錯誤:
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的新特性(續)
php5的發布計劃
在前面的文章中我們提到,“根據zend公司2003年4月1日發布的訊息的話,現在的應該就是beta release了”,但是開發者內部討論的結果是,beta為時尚早,而且有可能不是beta release.
對這方面動向有興趣的可以參照 news://news.php.net/ 上所公布的信息 php.version5.dev:372
在這個文件中,php5的發布計劃又重新回到了一張白紙,而另一方面,zend engine2的開發正在著手進行中。php5的release其實大體就是盼望著“快點到年終吧”。
php5的新特性
接著我們來看一下在前面所講到的其他一些關于類的新增的機能
■名空間
php5支持名空間。因此,我們可以在名空間內裝入類、變量、常量、函數。
在php4的scope中,只有global、函數內、類內這三個種類,所以要特別注意如果不注意的話,將會很容易“污染”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常量的優先級要高。
在這里const是預約語,因此在class名和函數名中使用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的優先級較高,被顯示為「class constant」。
■對象變量
即使是在類沒有被實例化狀態下,對象變量也能準確的按照指定的值被初始化。訪問的方法如下:
類名::$變量名
php代碼:--------------------------------------------------------------------------------
class hoge {
static $my_static = 5;
}
print hoge::$my_static;
?>
--------------------------------------------------------------------------------
■統一構建器
在生成對象的時候,能夠自動被調用的方法被稱作“構建器”。
php4中的構建器,是與class名相同的方法名。這是與java和c++相同的地方,因此,對于一些用慣了的人來說,不會有別扭感。但是,如果要從子類中調用父類的構建器的話,在php中就必須特意寫上父類的名字。
在php中,父類的構建器不能被自動調用,因此,情況就比較多。
在php5中,統一采用了__constructor這個構建器名稱,不管class名是什么,凡是被稱為__construct()的,都被當作構建器來處理。
另外,考慮到同php4的互換性,假如存在于class名相同的以前的構建器名,那么,優先使用那個構建器。
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運行終止時用register_shutdown_function()調用的函數,只有類似的實行方法。php5正式支持析構函數,能夠在類中指定對象釋放時的動作。
析構函數就是名為__destruct的方法。當對象內部的參照計數器變成0的時候,__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();
■訪問
在php4中,如果訪問了一個不存在的屬性,那么系統就會自動生成與之相對應的新屬性。
php代碼:--------------------------------------------------------------------------------
class hoge {
}
$obj = new hoge;
$obj->prop = "this is new property";
--------------------------------------------------------------------------------
如上所示,當把值代入一個不存在的屬性時,那個代入點就會自動生成一個新屬性。同樣的,訪問一個不存在的屬性,就如同被代入null值的變量一樣,不會發生錯誤。
在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';
--------------------------------------------------------------------------------
執行這一句時,因為在這個時候不存在屬性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改成存入文件或是數據庫會很有趣吧。實際上,在對象里面,我們能夠簡單的實現讓許多的復雜的操作。
與__set, __get多少有些不同,但是__call也能用來書寫不存在的方法,當我們向如下例子一樣調用對象的方法的時候,
$object->methodname();
如果這個類中不存在methodname這個方法,通常情況下,就會出現如下錯誤:
fatal error: call to undefined method class::methodname()
但是,如果這個類中存在__call這個方法,作為替代,__call就被調用。__call的參數有兩個,第一個參數是被叫出的方法名,第二個參數是保持了的被調用的參數的數組。考慮到有很多的使用方法,除了以下的例子外,還可以使用其它的方法。
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";
?>
網站運營seo文章大全提供全面的站長運營經驗及seo技術!