jocosn 2008-6-25 05:41 PM
PHP 5 的 OO 之路淺介
自行整理的 PHP5 新功能 OOP,紅色斜體字表你在寫程式碼時須自行替換為合法的識別字。內容有錯誤請留言。
-----------------------------------------
[color=DarkSlateGray]■ Classes and Objects[/color]
◆ declare class
[語法]
class [i][color=Red]Class-Name[/color][/i] {
[color=DarkGreen]// members,包括 methods(或稱 functions)、 data member(指 properties) 等[/color]
...........
}
[b][說明][/b]
定義類別需使用關鍵字「class」,後面指定「類別名稱」,並在大括號「{ }」內定義組成類別的成員。
類別名稱為英文字母部分不區分大小寫,否則會產生 redeclare 錯誤。如 class ABC 與 class aBc 為重複宣告。
[b][範例][/b]
// 類別
class TestClass {
function __construct() { // 建構子
echo "建構子... <br>";
}
function __destruct() { // 解構子
echo "解構子... <br>";
}
public function m() { // 方法
echo "方法... <br>";
}
public $p = "屬性... <br>"; // 屬性
}
$obj = new TestClass(); // 建立實體
echo $obj->p; // 呼叫屬性
$obj->m(); // 執行方法
unset($obj); // 釋放實體
[b][範例][/b]
class MyClass {
var $myVar1, $myStatus; // OK
$myVar2; // parse error, unexpected T_VARIABLE, expecting T_FUNCTION
public $myVar3; // OK
}
jocosn 2008-6-25 05:43 PM
[color=DarkSlateGray]■ create instance[/color]
建立類別的實體/物件(instance/object) 需使用「new」關鍵字。
[b][範例][/b]
class MyPerson {
// properties
private $name;
// methods
function setName($name) {
$this->name = $name;
}
function getName() {
return $this->name;
}
};
// create instances
$classmate1 = new MyPerson();
$classmate1->setName("John");
$classmate2 = new Person();
$classmate2->setName("Joe");
print $classmate1->getName() . "<br>";
print $classmate2->getName(). "<br>";
[color=DarkSlateGray]■ 成員呼叫[/color]
1. 使用物件的成員須使用 -> 運算子
[b][語法][/b]
[i][color=Red]$object[/color][/i]->[color=Red][i]property-name[/i][/color]
[i][color=Red]$object[/color][/i]->[i][color=Red]method-name[/color][/i]([[color=Red][i]arg[/i][/color], ... ])
2. 未建立類別的物件(object instance)前,可使用 :: 操作符號直接引用類別內的方法。
[b][語法][/b] [i][color=Red]class-name[/color][/i]::[color=Red][i]method-name[/i][/color]
[b][範例][/b]
class MyClass {
var $myVar = 'Non-Static Property ... <br>' ;
static public $myStaticVar = 'Static Property ... <br>';
function non_static_method_1() {
echo 'Non-Static Method ! <br>';
}
function non_static_method_2() {
$this->myVar = 'set $myVar property ...';
echo '$this->myVar' . $this->myVar . '<br>';
echo 'Non-Static Method ! <br>';
}
static function static_method() {
echo 'Static Method ! <br>';
self::non_static_method_1(); // OK
self::non_static_method_2();
}
}
$t = new MyClass();
print '$t->myStaticVar :'.$t->myStaticVar; // 顯示「$t->myStaticVar :」
MyClass::non_static_method_1(); // Non-Static Method !
MyClass::non_static_method_2(); // Fatal error: Using $this when not in object context
print MyClass::$myVar; // Fatal error: Access to undeclared static property: MyClass::$myVar
jocosn 2008-6-25 05:46 PM
[color=DarkSlateGray]■ 存取修飾子 (Access Modifier -public/private/protected)[/color]
property 或 method 可使用存取修飾子控制存取權限。
•public 可由類別內部或外部存取。預設值。
•protected 只能由類別內部或衍生類別所呼叫。
•private 只能由類別內部存取。設定為 private 的 member 不能被繼承,衍生類別無法呼叫。
[b][範例][/b]
public class A {
public $p;
public function m( ) {
print "Class A ...";
}
}
class B extends A {
public function m( ) {
print "Class B ...";
}
}
$obj = new B;
$obj->p = "Hello World!";
print $obj->p; // Hello World!
[b][範例][/b]
private class MyClass {
private $id = 18;
public function getId() {
return $this->id;
}
}
$obj = new MyClass;
$obj->id = "SN 566002-5698"; // Fatal error: Cannot access private property MyClass::$id
[b][範例][/b] call private property inherited from another class
class X {
private $Name;
}
class Y extends X { }
$obj = new Y;
$obj->Name = "Joe";
$obj->Name2 = "Jolin";
print_r($obj);
/* 執行結果
Y Object
(
[Name:private] =>
[Name] => Joe
[Name2] => Jolin
)
*/
[color=DarkSlateGray]■ Constructor (建構子)[/color]
1. 建構子會在物件產生時(使用 new 關鍵字) 自動執行。建構子可接受參數,且必須宣告為 public。
2. 建構子無法傳回值(return a value)。可藉由丟出 exception 做錯誤處理。
[b][方法一][/b] 定義一個與 class 同名的 member function,可接受參數。
[b][方法二][/b] 定義 __construct 方法 (PHP 5+ 版本)
void __construct ( [[i][color=Red]mixed args[/color][/i][, ...]] )
[b][範例][/b]
class Person {
function __construct($name) {
$this->name = $name;
}
function getName() {
return $this->name;
}
private $name;
}
$classmate1 = new Person("John");
$classmate2 = new Person("Joe");
print $classmate1->getName() . "<br>";
print $classmate2->getName() . "<br>";
[color=Purple]◆ Calling Parent Constructor[/color]
建立 derived class 的物件時,parent class 的 constructor 不會自動被執行(PHP 沒有建構子串接機制,Cascading Constructors),子類別的建構子會完全覆載父類別的建構子,若須要父類別參與物件初始作業的處理,須在子類別的建構子中呼叫父類別的建構子。
[b][語法][/b] [color=Red][i]parent[/i][/color]::__construct(...)
[b][範例][/b]
class BaseClass {
function __construct() {
print "In BaseClass constructor <br>";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor <br>";
}
}
$obj = new BaseClass();
$obj = new SubClass();
[color=DarkSlateGray]■ Destructor 解構子(PHP 5+)[/color]
void __destruct ( void )
1. 解構子為物件被釋放時會自動被呼叫的特殊函數,該函數不能定義參數。
2. 解構子內若試圖丟出 exception 會產生 fatal error。
3. 呼叫 parent class 的 destructor 須另外使用「parent::__destruct(...)」呼叫。
[b][範例][/b]
class MyClass {
function __destruct() {
print "An object of type MyClass is being destroyed.";
}
}
$obj = new MyClass();
$obj = NULL;
jocosn 2008-6-25 05:47 PM
[color=DarkSlateGray]■ 生存空間 (Scope)[/color]
• PHP 的生存空間有:
1) 全域生存空間 (Global Scope)
2) 局部生存空間 (Local Scope)
a) 類別生存空間 (Class Scope)
b) 函式生存空間 (Function Scope)
•任何一個生存空間中所定義的函式或變數,對其它空間來說都是屬於不可見的(會被隱藏)
如函式 X 的生存空間,對於函式 Y 的生存空間是屬於不可見的。
[color=DarkSlateGray]■ 使用 $this 存取 Methods 與 Properties[/color]
1. 每個類別都有一個 $this 虛擬變數(pseudo-variable) 表示該類別本身的物件。
2. 任何一個 method 內(包括建構子),變數 $this 都會參照(reference) 到呼叫目前 method 的物件。
藉由 $this 變數配合符號 -> 可在 method 內呼叫或存取同一個類別裡的其它成員,亦即去存取歸屬於目前物件的 properties、或呼叫目前物件的其它 methods,以便讓類別成員相互之間可以進行互動。
3. 在 static methods 內並沒有定義 $this 變數。
[b][範例][/b]
class A {
function foo() {
if (isset($this)) {
echo '$this is defined (';
echo get_class($this);
echo ") <br>";
} else {
echo "\$this is not defined. <br>";
}
}
}
class B {
function bar() {
A::foo();
}
}
$a = new A();
$a->foo();
A::foo();
$b = new B();
$b->bar();
B::bar();
[color=DarkSlateGray]■ Class Type Hints in Function Parameters[/color]
PHP 允許設定函式或方法的參數型態。亦即可以在參數前加上類別型態。
[b][範例][/b]
function onlyAllowDemoClassObjects($obj) {
if (!($obj instanceof DemoClass)) {
die("Only objects of type DemoClass can be sent to this function");
}
...
}
可改寫成
function onlyAllowDemoClassObjects(DemoClass $obj) {
...
}
[color=DarkSlateGray]■ final 類別[/color]
宣告 final 的類別不能有子類別
[b][範例][/b]
final class MyBaseClass {
......
}
class MyConcreteClass extends MyBaseClass { // error
......
}
jocosn 2008-6-25 05:49 PM
[color=DarkSlateGray]■ Cloning Objects (請注意等號&下底線數目)[/color]
1. PHP4 使用指派運算子(=) 可複製(copy)物件;使用傳參考方式,會指向(point to)相同的物件。
2. PHP5 將指派運算(=) 視為傳參考,會指向相同的物件。若要複製物件,須使用「clone」關鍵字。
使用 clone 複製物件時,會先搜尋該物件是否有定義 __clone 方法,並依照該方法的定義內容來複製物件;否則會自動複製每個屬性(copy each member variable)。
__clone 方法無法直接透過物件呼叫。
3. 運算子「===」可檢驗判別變數是否指向相同物件。
[b][範例][/b] PHP 4
$var1 = $object; // $var1 與 $object 是不同物件
$var2 = &$object; // $var2 與 $object 是相同物件
[b][範例][/b] PHP 5
$var1 = $object; // $var1 與 $object 是相同物件
$var2 = clone $object; // $var2 與 $object 是不同物件
[b][範例][/b]
class MyClass {
public $var = 1;
}
$obj1 = new MyClass();
$obj2 = $obj1;
$obj2->var = 2;
print $obj1->var; // PHP4 --> 1 ; PHP5 --> 2
$obj3 = clone $obj1;
$obj3->var = 5;
print $obj1->var; // PHP5 --> 2
[b][範例][/b] new object to not point at the same file handle, but to open a new one itself so that it has its own private copy
class MyFile {
function setFileName($file_name) {
$this->file_name = $file_name;
}
function openFileForReading() {
$this->file_handle = fopen($this->file_name, "r");
}
function __clone() {
if ($this->file_handle) {
$this->file_handle = fopen($this->file_name, "r");
}
}
private $file_name;
private $file_handle = NULL;
}
[color=DarkSlateGray]■ Inheritance[/color]
1. 使用「extends」關鍵字可建立繼承關係。
2. 被繼承的類別稱為基底類別(base class)、父類別或超類別(superclass);繼承基底類別的新類別稱為子類別(subclass)、衍生類別(derived class)或擴充類別。
3. PHP 無法同時繼承多個類別,亦即不允許多重繼承。
4. 繼承機制作用在於不須重建已存在於父類別的成員。
[b][範例][/b]
class A {
......
}
class B extends A {
......
}
jocosn 2008-6-25 05:50 PM
[color=DarkSlateGray]■ Overriding Methods (Redefined Functions)[/color]
1. PHP 允許在 subclasses 內重覆定義同名的函式,稱為方法的覆寫(Overriding)。
2. 呼叫 parent class 被覆寫的 method :
[b][語法一][/b] 使用父類別名稱呼叫
[i][color=Red]superclass-name[/color][/i]::[color=Red][i]method-name[/i][/color](...)
[b][語法二][/b] 使用關鍵字 parent 呼叫 (此種方式不須牢記父類別名稱)
[i][color=Red]parent[/color][/i]::[color=Red][i]method-name[/i][/color](...)
[b][範例][/b]
class MyA {
function info( ) {
return "MyA ...";
}
}
class MyB extends MyA {
function info( ) {
return parent::info( )."MyB ...";
}
}
class MyC extends MyB {
function info( ) {
return MyA::info( ) . MyB::info( ) . "MyC ...";
}
}
$objA = new MyA;
$objB = new MyB;
$objC = new MyC;
print $objA->info( ); // prints "MyA ..."
print $objB->info( ); // prints "MyA ...MyB ..."
print $objC->info( ); // prints "MyA ...MyB ...MyC ..."
[color=DarkSlateGray]■ Objects Within Objects[/color]
1. PHP 允許在 object 內含其它 object。
2. 存取物件內的物件須使用關鍵字「new」建立欲存取之類別的物件。
[b][範例][/b]
class FClass {
public function myFunc( ) {
print "Hello World.";
}
}
class A {
public $var;
}
$myObj = new A;
$myObj->var = new FCLASS; // created with "new"
$myObj->var->myFunc(); // Hello World.
[color=DarkSlateGray]■ Polymorphism 多型[/color]
若 derived class 與 parent class 有相同名稱的函數,則 derived class 會取代 parent class 的函數。
[b][範例][/b]
class A {
function F() {
print "Error: This method should be re-implemented in the children";
}
}
class B extends A {
function F() {
print "Polymorphism ....(B)";
}
}
class C extends A {
function F() {
print "Polymorphism ....(C)";
}
}
function printTheRightFunc($obj) {
if ($obj instanceof A) {
$obj->F();
} else {
print "Error: Passed wrong kind of object";
}
print "<br>";
}
printTheRightSound(new B()); // Polymorphism ....(B)
printTheRightSound(new C()); // Polymorphism ....(C)
jocosn 2008-6-25 05:53 PM
[color=DarkSlateGray]■ MAGIC METHODS[/color]
Method and function names beginning with a double underscore—such as __construct(), __destruct(), and __autoload()—are reserved in PHP and are often referred to as magic.
[color=Purple]◆ __construct[/color]
void __construct ( [[color=Red][i]mixed args [/i][/color][, ...]] )
Called when a new instance of the class is created.
Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
[b][範例][/b]
class BaseClass {
function __construct() {
print "In BaseClass constructor";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor";
}
}
[color=Purple]◆ __destruct[/color]
void __destruct ( void )
Called when an instance of the class passes out of memory; this happens when you
either unset() the instance or a script finishes running.
[color=Purple]◆ __autoload[/color]當使用到 undeclared class 時(如建立物件、使用 static member),會自動呼叫 __autoload 函數。
__autoload 函數會傳入所呼叫的 class 名稱作為參數,可用來作為動態引入外部檔案中的 class 定義來避免發生錯誤。
[b][範例][/b] 從 MyClass1.php、MyClass2.php 檔案分別載入 MyClass1、MyClass2 類別,省略事先特別指定引入(include、或require)某個檔案動作
function __autoload($class_name) {
require_once $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
◆ __clone
1. PHP 5 後,傳遞物件時預設行為是使用參考進行傳遞。若需要用到某物件的副本(copy of an object),可使用 __clone() 方法產生副本。
2. 欲製作物件的副本須使用 clone 關鍵字。
3. 物件複製時,可使用自行定義的 __clone() 方法,若使用者未自行定義,則會使用預設的 __clone 方法,預設會拷貝所有的 properties。
4. __clone 函數無法直接呼叫,需使用下列語法複製物件:
[b][語法][/b] [i][color=Red]$replication[/color][/i] = clone [color=Red][i]$src[/i][/color];
[b][範例][/b]
class MyCar {
private $gas = 0;
private $color = "blue";
function addGas($amount) {
$this->gas = $this->gas + $amount;
echo "$amount gallons added to gas tank";
}
function __clone() {
$this->gas = 0;
}
}
$firstCar = new MyCar;
$firstCar->addGas(10); // 10 gallons added to gas tank
$secondCar = clone $firstCar; // $secondCar is blue but contains 0 gallons of gas
[color=Purple]◆ __get 和 __set、__isset 和 __unset、__call[/color]
void __set ( string property-name, mixed property-value )
mixed __get ( string property-name )
bool __isset ( string property-name ) →PHP 5.1.0
void __unset ( string property-name ) →PHP 5.1.0
mixed __call ( string method-name, array arguments )
1. 藉由 __call,__get 和 __set,__isset 和 __unset 函數可對類別成員進行多載化(overload,重載) 動作
__get() 與 __set() 可取得或設定某物件屬性(property)。
__call() can be used for a variety of purposes.
2. 當存取物件未定義的成員時,會自動呼叫 __call、__get、__set 方法
PHP 中若嘗試存取類別中不存在的屬性時,會自動產生該屬性。但是若類別裡有定義 __set、__get 函數時,則會呼叫 __set、__get 函式進行處理。
若是嘗試呼叫類別中不存在的函式時,會產生「Fatal error: Call to undefined method」的錯誤。 但是若類別裡有定義 __call 函數時,會自動呼叫 __call 函式進行處理。
3. PHP 5+ 所有的 overloading methods 必須宣告為 public,且不能宣告為 static
[b][範例][/b]
class StrictCoordinateClass {
private $arr = array('x' => NULL, 'y' => NULL);
function __get($property) {
if (array_key_exists($property, $this->arr)) {
return $this->arr[$property];
} else {
print "Error: Can't read a property other than x & y <br>";
}
}
function __set($property, $value) {
if (array_key_exists($property, $this->arr)) {
$this->arr[$property] = $value;
} else {
print "Error: Can't write a property other than x & y <br>";
}
}
} // class StrictCoordinateClass
$myObj = new StrictCoordinateClass();
$myObj->x = 1;
print $myObj->x . "<br>";
$myObj->n = 2;
print $myObj->n;
/* 執行結果
1
Error: Can't write a property other than x & y
Error: Can't read a property other than x & y
*/
[b][範例][/b]
class MyClass {
var $x = array(1, 2, 3);
function __call($m, $a) {
print "Method $m called:\n";
var_dump($a);
return $this->x;
}
}
$obj = new MyClass();
$a = $obj->test(1, "string here", 5.2, true);
var_dump($a);
/*
Method test called:
array(4) {
[0]=>
int(1)
[1]=>
string(11) "string here"
[2]=>
float(5.2)
[3]=>
bool(true)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
*/
[b][範例][/b]
/* 建立委派模組(delegation model)
an instance of the class HelloWorldDelegator delegates all method calls to an
instance of the HelloWorld class
*/
class HelloWorld {
function display($count) {
for ($i = 0; $i < $count; $i++) {
print "Hello, World\n";
}
return $count;
}
}
class HelloWorldDelegator {
function __construct() {
$this->obj = new HelloWorld();
}
function __call($method, $args) {
return call_user_func_array(array($this->obj , $method), $args);
}
private $obj;
}
$myObj = new HelloWorldDelegator();
print $myObj->display(3);
/* 執行結果
Hello, World
Hello, World
Hello, World
3
*/
jocosn 2008-6-25 05:54 PM
後面懶的貼,請自行下載 mht 格式。
無條件歡迎任何形式的轉貼(部份或全部內容皆可)、影印自用、或任何無商業上金錢報償的分享與修改,只要不做商業用途皆可,不須另外通知本人。
MHT 格式下載(IE 可直接開啟):
[url]http://www.badongo.com/file/7938155[/url]