淺談PHP物件導向程式設計

wx1234cn發表於2019-02-16

一、PHP物件導向程式設計基礎實踐

<?php
/*
*    通過物件的程式設計方式,可將實現生活中的一切事物以物件的形式表現出來。便於理解、維護、擴充套件等;
*    本示例:定義一個“人”類
*    $name : 物件中的成員屬性,在此類中表示人的姓名
*    say() : 物件中的成員方法,在此類中表示人說話的方法
*    $this : PHP中的偽變數,表示自身的類
*    __construct() : php中的魔術方法,建構函式,在例項化類時自動執行
*    __destruct() : php中的魔術方法,解構函式,當類呼叫完成後自動執行
*/
class Human
{
    public $name;
    public $sex;
    public $age;
    public function __construct($name,$sex,$age) 
    {
        $this->name = $name;
        $this->sex = $sex;
        $this->age = $age;
    }
    public function say()
    {
        echo `大家好,我的名字叫`.$this->name.`,今年`.$this->age.`歲,我的性別是`.$this->sex;
    }
    public function __destruct()
    {
        $this->name = null;
        $this->sex = null;
        $this->age = null;
    }
}
//例項化“人”類
$male = new Human("張三","男","20");
//呼叫“人”類說話的方法
$male->say();

//輸出結果:大家好,我的名字叫張三,今年20歲,我的性別是男
?>

二、PHP物件導向高階程式設計實踐

知識點:類的繼承、方法重寫、訪問控制、static關鍵字、final關鍵字、資料訪問、介面、多型、抽象類

2.1、類的繼承:extends 關鍵字
例如:一員執行員、一位主持人,他們有人類共同的行為方法,但他們都有自己不同的特長專業。因此在程式設計時需要給他們建立一個父類並繼承;

<?php
/*
*    建立一個“人”類做為父類,繼承的子類都擁有其父類的成員屬性、方法
*/
class Human
{
    public $name;
    public function say()
    {
        echo "父類說話的方法,姓名:".$this->name."
";
    }
    public function eat()
    {
        echo "父類吃飯的方法
";
    }
}
/*
*    建立一個“運動員”類,繼承“人”類
*    extends : 關鍵字,繼承某個類
*/
class Sport extends Human
{
    public $type;    
    public function __construct($name,$type)
    {
        $this->name = $name;    //給父類 $name 屬性賦值
        $this->type = $type;    
    }
    public function run()
    {
        $this->say();   //呼叫父類“說話”的方法
        echo "我在正跑步,我是一員".$this->type."運動員.....
";
    }
}
/*
*    建立一個“主持人”類,繼承“人”類
*    extends : 關鍵字,繼承某個類
*/
class Host extends Human
{
    public $television; 
    public function __construct($name,$television)
    {
        $this->name = $name;    
        $this->television= $television;   
    }
    public function perform()
    {
        $this->eat();   //呼叫父類“吃飯”的方法
        echo "我在正表演一個節目,我是".$this->television."電視臺的一名主持人.....
";
    }
}

//例項化“運動員”類
$nba = new Sport("喬丹","籃球");
$nba->run();

//例項化“主持人”類
$tv = new Host("張三","北京衛視");
$tv->perform();

//輸出結果:
//父類說話的方法,姓名:喬丹 我在正跑步,我是一員籃球運動員..... 
//父類吃飯的方法 我在正表演一個節目,我是北京衛視電視臺的一名主持人.....
?>

2.2、方法重寫:子類重寫父類的方法

<?php
class Human
{
    public function say()
    {
        echo "父類說話的方法";
    }
}
class Sport extends Human
{
    //重寫父類“說話”的方法
    public function say()
    {
        echo "子類說話的方法";
    }
}
$nba = new Sport();
$nba->say();
//輸出結果:子類說話的方法
?>

2.3、訪問控制:public 、 protected 、private 關鍵字
public:定義公共的成員屬性或方法,任何地方都可使用
protected : 定義受保護的成員屬性或方法,只允許類本身或子類使用
private : 定義私有的成員屬性或方法,只允許類的本身使用

<?php
class Human
{
    public $name;
    protected $sex;
    private $age;
    
}
//例項化物件,給公共屬性賦值可正常輸出結果,外部不能給protected、private受保護的成員屬性賦值或使用
$worker = new Human();
$worker->name = "張三";
echo $worker->name;

?>

2.4、static(靜態)關鍵字
1)、靜態屬性用於儲存類的公有資料;
2)、靜態方法裡面只能訪問靜態屬性或方法,不能使用 $this 偽變數;
3)、靜態成員不需要通過 new 關鍵字來例項化物件就可訪問使用;

<?php
class Human
{
    static $name = "張三";
    static function say()
    {
        echo "我的姓名叫:".self::$name;
    }
}
//外部使用靜態成員屬性或方法
echo Human::$name;
Human::say();

//輸出結果:張三  我的姓名叫:張三
?>

2.5、final關鍵字:不允許成員方法被重寫,不允許被繼承
例:1、對於父類“吃飯”這個方法,不希望子類重寫它;2、對於“運動員”這個類,不希望它再建立子類;

<?php
class Human
{
    final public function eat()
    {
        echo "父類吃飯的方法,不允許子類重寫";
    }
}
final class Sport extends Human
{
    public function eat()
    {
        echo "子類吃飯的方法。此時程式將會報致命錯誤";
    }
}
//建立一個類繼承 Sport 這個類。此時程式也將會報致命錯誤。因為 Sport 類不允許再建立子類
class Student extends Sport
{
    public $name;
}

//例項化 Sport 類 ,呼叫 eat() 方法
$nba = new Sport();
$nba->eat();

//例項化 Student 類 ,給 name 屬性負值
$obj = new Student();
$obj->name = "張三";

//輸出結果:Fatal error: Cannot override final method Human::eat() in ******.php on line 15
//Fatal error: Class Student may not inherit from final class (Sport) in ****.php on line 20
?>

2.6、資料訪問:$this 、 self 、parent 關鍵字
$this : 偽變數,代表類的本身,可訪問本類及父類中的成員屬性與方法。
self : 訪問類中的靜態成員屬性或方法
parent :訪問父類的成員屬性或方法

<?php
class Human
{
    static $name = "張三";
}
class Sport extends Human
{
    static function getParentName()
    {
        echo parent::$name;
    }
    public function get() 
    {
       self::getParentName(); 
    }
}
$obj = new Sport();
$obj->get();
//輸出結果:張三
?>

2.7、介面:把不同類的共同行為方法進行定義,但不具體實現,由子類來實現具體的方法;
例如:人會吃飯,動物也會吃飯,甚至有些植物也會吃飯,但他們吃飯的方式不一樣,因此這時需要定義一個介面類,具體的方式由子類來實現;
定義介面關鍵字:interface
實現介面方法關鍵字:implements

<?php
//定義一個介面類,有吃飯的方法,但不具體實現。
interface ICanEat
{
    public function eat($food);
}
class Human implements ICanEat
{
    //eat()方法必須由子類來實現,否則程式將報致命錯誤
    public function eat($food) 
    {
        echo "I`m eating ".$food;
    }
}
class Animal implements ICanEat
{
    public function eat($food)
    {
        echo "It`s eating ".$food;
    }
}
//例項化一個“人”類
$people = new Human();
$people->eat(`rice`);

//例項化一個“動物”類
$monkey = new Animal();
$monkey->eat(`banana`);

//輸出結果:I`m eating rice
// It`s eating banana

?>

2.8、多型:比如介面A有兩個實現B和C,B和C對A介面裡面定義的方法實現可以是不同的,這種現象稱之為多型;
上述例項中,ICanEat介面定義了一個eat()方法,人類吃米飯,猴子吃香蕉。他們都實現了一個“吃”的方法,但他們吃東西有不同的行為,稱之為多型;

2.9、抽象類:介入介面與類的定義之間,允許類裡面一部分方法不實現,實現一部分有相同功能且不會更改的方法。然而介面類裡面不允許有任何實現的方法。
例如:人和動物都具有吃飯與呼吸的方法,除吃飯不同以外,呼吸方法是相同的,此時需要定義一個抽象類來實現。
定義抽象類關鍵字:abstract

<?php
//定義一個抽象類,裡面有吃飯和呼吸的方法。呼吸方法需要在抽象類中具體實現
abstract class ICanEat
{
    abstract function eat($food);
    public function breath()
    {
        echo `Breath use the air...`;
    }
}
class Human extends ICanEat
{
    public function eat($food)
    {
        echo "I`m eating ".$food;
        $this->breath();
    }
}
//例項化“人”類
$people = new Human();
$people->eat(`rice`);
//輸出結果:I`m eating rice Breath use the air...
?>

三、PHP物件導向程式設計特殊實踐
PHP語言特定的一些魔術方法:

<?php
class Object
{
    public function __construct()
    {
        echo "當類在被例項化的時候,自動執行該函式";
    }
    public function __toString()
    {
        return "當物件被當作字串形式輸出時,自動執行該函式";
    }
    public function __invoke($value)
    {
        echo "當物件被當作函式呼叫時,自動執行該函式".$value;
    }
    /*
    *    當物件訪問不存在的方法時,自動執行該函式。也稱之為“方法過載”
    *    $fun : 方法名稱
    *    $param : 傳遞的引數
    */
    public function __call($fun,$param)
    {
        echo "呼叫".$fun."方法不存在,傳遞的引數".implode(`,`,$param);
    }
    /*
    *    當物件訪問不存在的靜態方法時,自動執行該函式。
    *    $fun : 方法名稱
    *    $param : 傳遞的引數
    */
    static function __callStatic($fun,$param)
    {
        echo "呼叫".$fun."靜態方法不存在,傳遞的引數".implode(`,`,$param);
    }
    public function __get($key)
    {
        echo "當讀取物件中不可訪問(未定義)的屬性值時,自動呼叫該函式。".$key."屬性不可訪問或未定義";
    }
    public function __set($key,$value)
    {
         echo "當給物件中不可訪問(未定義)的屬性賦值時,自動呼叫該函式。".$key."屬性不可訪問或未定義,值".$value;
    }
    public function __isset($key)
    {
        echo "判斷物件中的屬性不存在時,自動執行該函式。屬性:".$key."值未定義";
    }
    public function __unset($key)
    {
        echo "釋放物件中的不存在的屬性值時,自動執行該函式。屬性:".$key."值未定義";
    }
    public function __clone()
    {
        echo "當物件被克隆時,自動執行該函式。";
    }
    public function __destruct()
    {
        echo "當物件執行完成後,自動執行該函式";
    }
}
$obj = new Object();    //例項化物件時,呼叫__construct()方法
echo $obj;              //將物件以字串形式輸出時,呼叫__toString()方法
$obj(123);              //當物件以函式形式呼叫時,執行__invoke()方法
$obj->runTest();        //當呼叫物件中不存在的方法時,執行__call()方法
$obj::runTest();        //當呼叫物件中不存在的靜態方法時,執行__callStatic()方法
$obj->name;             //當呼叫物件中不存在的成員屬性時,執行__get()方法
$obj->name = "張三";    //當給物件中不存在的成員屬性賦值時,執行__set()方法
isset($obj->name) ? 1 : 0;     //判斷物件中不存在的成員屬性時,執行__isset()方法
unset($obj->name);      //釋放物件中的不存在的屬性值時,執行__unset()方法
$obj2 = clone $obj;     //當物件被克隆時,執行__clone()方法
                        //物件執行完畢,執行__destruct()方法
?>

相關文章