PHP新手之學(xué)習(xí)類與對(duì)象
PHP 5 引入了新的對(duì)象模型(Object Model)。完全重寫(xiě)了 PHP 處理對(duì)象的方式,允許更佳性能和更多特性。
一、基本概念
1、class
每個(gè)類的定義都以關(guān)鍵字 class 開(kāi)頭,后面跟著類名,可以是任何非 PHP 保留字的名字。后面跟著一對(duì)花括號(hào),里面包含有類成員和方法的定義。偽變量 $this 可以在當(dāng)一個(gè)方法在對(duì)象內(nèi)部調(diào)用時(shí)使用。$this 是一個(gè)到調(diào)用對(duì)象(通常是方法所屬于的對(duì)象,但也可以是另一個(gè)對(duì)象,如果該方法是從第二個(gè)對(duì)象內(nèi)靜態(tài)調(diào)用的話)的引用??聪旅胬樱?/p>
Example#1 面向?qū)ο笳Z(yǔ)言中的 $this 變量
- <?php
- class A
- {
- function foo()
- {
- if (isset($this)) {
- echo '$this is defined (';
- echo get_class($this);
- echo ")\n";
- } else {
- echo "\$this is not defined.\n";
- }
- }
- }
- class B
- {
- function bar()
- {
- A::foo();
- }
- }
- $a = new A();
- $a->foo();
- A::foo();
- $b = new B();
- $b->bar();
- B::bar();
- ?>
上例將輸出:
- $this is defined (a)
- $this is not defined.
- $this is defined (b)
- $this is not defined.
Example#2 簡(jiǎn)單的類定義
- <?php
- class SimpleClass
- {
- // 成員聲明
- public $var = 'a default value';
- // 方法聲明
- public function displayVar() {
- echo $this->var;
- }
- }
- ?>
Example#3 類成員的默認(rèn)值
- <?php
- class SimpleClass
- {
- // 無(wú)效的類成員定義:
- public $var1 = 'hello '.'world';
- public $var2 = <<<EOD
- hello world
- EOD;
- public $var3 = 1+2;
- public $var4 = self::myStaticMethod();
- public $var5 = $myVar;
- // 正確的類成員定義:
- public $var6 = myConstant;
- public $var7 = self::classConstant;
- public $var8 = array(true, false);
- }
- ?>
2、new
要?jiǎng)?chuàng)建一個(gè)對(duì)象的實(shí)例,必須創(chuàng)建一個(gè)新對(duì)象并將其賦給一個(gè)變量。當(dāng)創(chuàng)建新對(duì)象時(shí)該對(duì)象總是被賦值,除非該對(duì)象定義了構(gòu)造函數(shù)并且在出錯(cuò)時(shí)拋出了一個(gè)異常。
Example#4 創(chuàng)建一個(gè)實(shí)例
- <?php
- $instance = new SimpleClass();
- ?>
復(fù)制代碼當(dāng)把一個(gè)對(duì)象已經(jīng)創(chuàng)建的實(shí)例賦給一個(gè)新變量時(shí),新變量會(huì)訪問(wèn)同一個(gè)實(shí)例,就和用該對(duì)象賦值一樣。此行為和給函數(shù)傳遞入實(shí)例時(shí)一樣。可以用克隆給一個(gè)已創(chuàng)建的對(duì)象建立一個(gè)新實(shí)例。
Example#5 對(duì)象賦值
- <?php
- $assigned = $instance;
- $reference =& $instance;
- $instance->var = '$assigned will have this value';
- $instance = null; // $instance and $reference become null
- var_dump($instance);
- var_dump($reference);
- var_dump($assigned);
- ?>
復(fù)制代碼上例將輸出:
- NULL
- NULL
- object(SimpleClass)#1 (1) {
- ["var"]=>
- string(30) "$assigned will have this value"
- }
3、extends
一個(gè)類可以在聲明中用 extends 關(guān)鍵字繼承另一個(gè)類的方法和成員。不能擴(kuò)展多個(gè)類,只能繼承一個(gè)基類。
被繼承的方法和成員可以通過(guò)用同樣的名字重新聲明被覆蓋,除非父類定義方法時(shí)使用了 final 關(guān)鍵字??梢酝ㄟ^(guò) parent:: 來(lái)訪問(wèn)被覆蓋的方法或成員。
Example#6 簡(jiǎn)單的類繼承
- <?php
- class ExtendClass extends SimpleClass
- {
- // Redefine the parent method
- function displayVar()
- {
- echo "Extending class\n";
- parent::displayVar();
- }
- }
- $extended = new ExtendClass();
- $extended->displayVar();
- ?>
上例將輸出:
- Extending class
- a default value
#p#
二、自動(dòng)加載對(duì)象
很多開(kāi)發(fā)者寫(xiě)面向?qū)ο蟮膽?yīng)用程序時(shí)對(duì)每個(gè)類的定義建立一個(gè) PHP 源文件。一個(gè)很大的煩惱是不得不在每個(gè)腳本(每個(gè)類一個(gè)文件)開(kāi)頭寫(xiě)一個(gè)長(zhǎng)長(zhǎng)的包含文件列表。
在 PHP 5 中,不再需要這樣了??梢远x一個(gè) __autoload 函數(shù),它會(huì)在試圖使用尚未被定義的類時(shí)自動(dòng)調(diào)用。通過(guò)調(diào)用此函數(shù),腳本引擎在 PHP 出錯(cuò)失敗前有了最后一個(gè)機(jī)會(huì)加載所需的類。
Note: 在 __autoload 函數(shù)中拋出的異常不能被 catch 語(yǔ)句塊捕獲并導(dǎo)致致命錯(cuò)誤。如果使用 PHP 的 CLI 交互模式 時(shí),Autoloading 不存在。
Example#1 Autoload 例子(本例嘗試分別從 MyClass1.php 和 MyClass2.php 文件中加載 MyClass1 和 MyClass2 類。)
- <?php
- function __autoload($class_name) {
- require_once $class_name . '.php';
- }
- $obj = new MyClass1();
- $obj2 = new MyClass2();
- ?>
三、構(gòu)造函數(shù)和析構(gòu)函數(shù)
1、構(gòu)造函數(shù)
- void __construct ([ mixed $args [, $... ]] )
PHP 5 允行開(kāi)發(fā)者在一個(gè)類中定義一個(gè)方法作為構(gòu)造函數(shù)。具有構(gòu)造函數(shù)的類會(huì)在每次創(chuàng)建對(duì)象時(shí)先調(diào)用此方法,所以非常適合在使用對(duì)象之前做一些初始化工作。
Note: 如果子類中定義了構(gòu)造函數(shù)則不會(huì)暗中調(diào)用其父類的構(gòu)造函數(shù)。要執(zhí)行父類的構(gòu)造函數(shù),需要在子類的構(gòu)造函數(shù)中調(diào)用 parent::__construct()。
Example#1 使用新標(biāo)準(zhǔn)的構(gòu)造函數(shù)
- <?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();
- ?>
復(fù)制代碼為了實(shí)現(xiàn)向后兼容性,如果 PHP 5 在類中找不到 __construct() 函數(shù),它就會(huì)嘗試尋找舊式的構(gòu)造函數(shù),也就是和類同名的函數(shù)。因此唯一會(huì)產(chǎn)生兼容性問(wèn)題的情況是:類中已有一個(gè)名為 __construct() 的方法,但它卻又不是構(gòu)造函數(shù)。
2、析構(gòu)函數(shù)
- void __destruct ( void )
PHP 5 引入了析構(gòu)函數(shù)的概念,這類似于其它面向?qū)ο蟮恼Z(yǔ)言,如 C++。析構(gòu)函數(shù)會(huì)在到某個(gè)對(duì)象的所有引用都被刪除或者當(dāng)對(duì)象被顯式銷毀時(shí)執(zhí)行。
Example#2 析構(gòu)函數(shù)示例
- <?php
- class MyDestructableClass {
- function __construct() {
- print "In constructor\n";
- $this->name = "MyDestructableClass";
- }
- function __destruct() {
- print "Destroying " . $this->name . "\n";
- }
- }
- $obj = new MyDestructableClass();
- ?>
復(fù)制代碼和構(gòu)造函數(shù)一樣,父類的析構(gòu)函數(shù)不會(huì)被引擎暗中調(diào)用。要執(zhí)行父類的析構(gòu)函數(shù),必須在子類的析構(gòu)函數(shù)體中顯式調(diào)用 parent::__destruct()。
Note: 析構(gòu)函數(shù)在腳本關(guān)閉時(shí)調(diào)用,此時(shí)所有的頭信息已經(jīng)發(fā)出。試圖在析構(gòu)函數(shù)中拋出一個(gè)異常會(huì)導(dǎo)致致命錯(cuò)誤。
#p#
四、訪問(wèn)控制
對(duì)屬性或方法的訪問(wèn)控制,是通過(guò)在前面添加關(guān)鍵字 public、protected 或 private 來(lái)實(shí)現(xiàn)的。由 public 所定義的類成員可以在任何地方被訪問(wèn);由 protected 所定義的類成員則可以被其所在類的子類和父類訪問(wèn)(當(dāng)然,該成員所在的類也可以訪問(wèn));而由 private 定義的類成員則只能被其所在類訪問(wèn)。
1、對(duì)類成員的訪問(wèn)控制
類成員都必須使用關(guān)鍵字public、protected 或 private 進(jìn)行定義
Example#1 聲明類成員
- <?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; // 這行能被正常執(zhí)行
- echo $obj->protected; // 這行會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- echo $obj->private; // 這行也會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- $obj->printHello(); // 輸出 Public、Protected 和 Private
- /**
- * Define MyClass2
- */
- class MyClass2 extends MyClass
- {
- // 可以對(duì) public 和 protected 進(jìn)行重定義,但 private 而不能
- protected $protected = 'Protected2';
- function printHello()
- {
- echo $this->public;
- echo $this->protected;
- echo $this->private;
- }
- }
- $obj2 = new MyClass2();
- echo $obj->public; // 這行能被正常執(zhí)行
- echo $obj2->private; // 未定義 private
- echo $obj2->protected; // 這行會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- $obj2->printHello(); // 輸出 Public、Protected2,但不會(huì)輸出 Private
- class Bar
- {
- public function test() {
- $this->testPrivate();
- $this->testPublic();
- }
- public function testPublic() {
- echo "Bar::testPublic\n";
- }
- private function testPrivate() {
- echo "Bar::testPrivate\n";
- }
- }
- class Foo extends Bar
- {
- public function testPublic() {
- echo "Foo::testPublic\n";
- }
- private function testPrivate() {
- echo "Foo::testPrivate\n";
- }
- }
- $myFoo = new foo();
- $myFoo->test(); // Bar::testPrivate
- // Foo::testPublic
- ?>
Note: 為了兼容性考慮,在 PHP 4 中使用 var 關(guān)鍵字對(duì)變量進(jìn)行定義的方法在 PHP 5 中仍然有效(只是作為 public 關(guān)鍵字的一個(gè)別名)。在 PHP 5.1.3 之前的版本,該語(yǔ)法會(huì)產(chǎn)生一個(gè) E_STRICT 警告。
2、對(duì)方法的訪問(wèn)控制
類中的方法都必須使用關(guān)鍵字public、protected 或 private 進(jìn)行定義。如果沒(méi)有設(shè)置這些關(guān)鍵字,則該方法會(huì)被設(shè)置成默認(rèn)的 public。
Example#2 聲明類中的方法
- <?php
- /**
- * Define MyClass
- */
- class MyClass
- {
- // 構(gòu)造函數(shù)必須是 public
- public function __construct() { }
- // 聲明一個(gè) public 的方法
- public function MyPublic() { }
- // 聲明一個(gè) protected 的方法
- protected function MyProtected() { }
- // 聲明一個(gè) private 的方法
- private function MyPrivate() { }
- // 這個(gè)方法也是 public 的
- function Foo()
- {
- $this->MyPublic();
- $this->MyProtected();
- $this->MyPrivate();
- }
- }
- $myclass = new MyClass;
- $myclass->MyPublic(); // 這行能被正常執(zhí)行
- $myclass->MyProtected(); // 這行會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- $myclass->MyPrivate(); // 這行會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- $myclass->Foo(); // Public、Protected 和 Private 都被調(diào)用了
- /**
- * Define MyClass2
- */
- class MyClass2 extends MyClass
- {
- // This is public
- function Foo2()
- {
- $this->MyPublic();
- $this->MyProtected();
- $this->MyPrivate(); // 這行會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤
- }
- }
- $myclass2 = new MyClass2;
- $myclass2->MyPublic(); // 這行能被正常執(zhí)行
- $myclass2->Foo2(); // Public 和 Protected 都被調(diào)用了,但 Private 不會(huì)被調(diào)用
- ?>
#p#
五、范圍解析操作符(::)
范圍解析操作符(也可稱作 Paamayim Nekudotayim)或者更簡(jiǎn)單地說(shuō)是一對(duì)冒號(hào),可以用于訪問(wèn)靜態(tài)成員、方法和常量,還可以用于覆蓋類中的成員和方法。
當(dāng)在類的外部訪問(wèn)這些靜態(tài)成員、方法和常量時(shí),必須使用類的名字。
把 Paamayim Nekudotayim 選作該操作符的名字似乎有些奇怪。然而,這是 Zend 開(kāi)發(fā)小組在寫(xiě) Zend Engine 0.5 (被用于 PHP 3 中)時(shí)所作出的決定。事實(shí)上這個(gè)詞在希伯萊文就是雙冒號(hào)的意思。
Example#1 在類的外部使用 :: 操作符
- <?php
- class MyClass {
- const CONST_VALUE = 'A constant value';
- }
- echo MyClass::CONST_VALUE;
- ?>
self 和 parent 這兩個(gè)特殊的關(guān)鍵字是用于在類的內(nèi)部對(duì)成員或方法進(jìn)行訪問(wèn)的。
Example#2 :: from inside the class definition
- <?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();
- ?>
當(dāng)一個(gè)子類覆蓋其父類中的方法時(shí),PHP 不會(huì)再執(zhí)行父類中已被覆蓋的方法,直到子類中調(diào)用這些方法為止。這種機(jī)制也作用于 構(gòu)造函數(shù)和析構(gòu)函數(shù)、重載 及 魔術(shù) 函數(shù)。
Example#3 調(diào)用父類的方法
- <?php
- class MyClass
- {
- protected function myFunc() {
- echo "MyClass::myFunc()\n";
- }
- }
- class OtherClass extends MyClass
- {
- // 覆蓋父類中的方法
- public function myFunc()
- {
- // 但仍然可以調(diào)用已被覆蓋的方法
- parent::myFunc();
- echo "OtherClass::myFunc()\n";
- }
- }
- $class = new OtherClass();
- $class->myFunc();
- ?>
希望通過(guò)以上內(nèi)容的介紹,能夠給你帶來(lái)幫助。
【編輯推薦】