查看完整版本: PHP 5 的 OO 之路淺介

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]
頁: [1]
查看完整版本: PHP 5 的 OO 之路淺介
提供高質素的醫護用品、租/售優質輪椅,物理治療設備,拐杖、老人椅、便椅、 血壓計等等