PHP面向對象(下)


單例模式

避免多人開發過程,實例化過多導致資源浪費, 限制只實例化一次的模式

構造方法不能執行則實例化失敗

思路 :

1、 保護或私有構造函數,房子外部實例化

2、 內部開發一個公共的靜態方法,負責實例化

3、 類有一個靜態屬性存放對象

<?php
class Single {
    //設置私有,保存實例狀態
    static protected $ins = NULL;
    //設置為私有,限制類外實例化,若沒有子類可去掉final
    final protected function __construct() {
        echo '實例化成功!';
    }
    //設置為靜態方法,類外能調用,實例化
    static public function getinstance() {
        //self代表當前類,判斷是否實例化
        if (self::$ins instanceof self) {
            return self::$ins;
        }
        self::$ins = new self();
        return self::$ins;
    }
}
$s1
= Single::getinstance(); $s2 = Single::getinstance();
//子類繼承父類若還要單例,要用final修飾父類構造方法, //阻止子類重寫構造方法自己去new的問題 class Single2 extends Single { }
$s11
= Single2::getInstance(); $s12 = Single2::getInstance();
if ($s11 === $s12) { echo "相等"; } ?>

 

final

final 不能修飾屬性

final 修飾方法,此方法能繼承,不能被重寫

final 修飾類,則此類 不能夠被繼承

 

魔術方法

是指某些情況下,會自動調用的方法,稱為魔術方法 ; 感覺一般都是那些權限不允許調用或者是不存在的屬性 才會觸發魔術方法

PHP面向對象中,提供了這幾個魔術方法,

他們的特點 都是以雙下划線__開頭的

__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state() 和 __clone()

__clone()   :克隆方法,當對象被克隆時,將會自動調用

 

 

__get() :當我們調用一個權限上不允許調用的屬性,和不存在的屬性時,__get魔術方法會自動調用,並且自動傳參,參數值是屬性名。醬紫就能避免系統會直接報錯,甚至fatal error,通過__get()我們就能自定義用戶訪問時的處理行為。注意如果是數組形式的話那么這里的$p相當於鍵值(即是下標)

流程:

$lily->age--無權-->__get(age);

$lily->friend--沒有此屬性-->__get('friend');

 

__set() :當為無權操作的屬性賦值時,或不存在的屬性賦值時,__set()自動調用,且自動傳2個參數 屬性 屬性值

 

 

__isset() :當用isset()判斷對象不可見的屬性時(protected/private/不存在的屬性)

會引發 __isset()來執行

 

isset($obj->xyz) 屬性為真,能說明  類聲明了一個xyz屬性嗎?

答:不能,因為isset($hua->tail)----沒有tail屬性---->__isset('tail');-à 如果__isset返回1則不能

 

__unset() : 當 用unset 銷毀對象的不可見屬性時,會引發 __unset();

 

__call($a,$b) : 調用不可見(不存在或無權限)的方法時,自動調用;前參數是方法名,后是傳參

 

__callStatic($a,$b) : 是調用不可見的靜態方法時,自動調用.

 

 

__call是調用不可見(不存在或無權限)的方法時,自動調用

$lisi->say(1,2,3);-----沒有say()方法----> __call('say',array(1,2,3))運行

 

 

__autoload() : 如果調用某個不存在的類,在報錯之前,系統會調用__autoload($n)函數,並把"類名"自動傳給__autoload函數我們自然可以在__autoload里 加載需要的類!

 

 

 

魔術方法的應用

TP中設置用戶注冊的做法: 把表單中接受到的信息,直接付給一個對象的屬性,然后

對象 add()  用sql語句寫到數據庫中

 

 

具體的思路

在一個類中設置一個空數組,利用__set()把傳進來的值放到數組中,然后利用 add方法 與數據庫交互 ; 醬紫避免了與其他同名屬性的沖突

都是使用魔法方法來進行操作

$date = array() 設置一個空數組

implode() :將數組按值進行分割

array_keys(array,value)  :獲得數組中鍵名並以數組的形式 ; 前者數組名必選 , 后者數組值可選  ;  只選前者則返回所有鍵名 ; 兩者選返回對應值得鍵名

 

2015/7/23

重載與重寫

重寫/覆蓋  override:子類重寫了父類的同名方法。只要子類有該方法只調用子類的無論參數是否一致

<?php
//模仿重載的功能
class Circle {
    public function area() {
        $a = func_get_args();
        $num = count($a);
        if ($num == 0) {
            echo '傳入參數' . "\n";
        } else if ($num == 1) {
            echo 3.14 * $a[0] . "\n"; //學會利用已有的條件進行分析
            
        } else if ($num == 2) {
            echo $a[0] * $a[1] . "\n";
        }
    }
}
$c
= new Circle(); $c->area(); $c->area(3);
class P { public function a() { echo "nihao"; } }
$b
= new P(); $b->a(2123, 'sdf'); ?>

 

重載 overload: 指存在多個同名方法,但參數類型/個數不同,傳不同的參數,調用不同的方法。但是在PHP中,不允許存在多個同名方法.因此,不能夠完成java,c++中的這種重載

但是,PHP的靈活,能達到類似的效果

<?php 
    function __autoload($n){
        require('./' . $n . '.php');
        echo "加載成功!";
    } 

    $test = new autoload_class();
    $test->say();
 ?>

 

常量 (常量名全大寫,不帶$)

普通常量 :define('常量名',常量值); 全局有效.無論是頁面內,函數內,類內,都可以訪問 ;

類內常量 : 類常量 在類內用 const 聲明即可;前面不用加修飾符,;且權限是public的,即外部也可以訪問

作用域在類內,類似於靜態屬性 ;又是常量,則不可改.

其實就是"不可改變的靜態屬性",即是能夠 類名::常量名 訪問

 

 

 

魔術常量

1:無法手動修改他的值,所以叫常量

2:但是值又是隨環境變動的,所以叫魔術

 

__FILE__  返回當前文件的路徑+文件名

在框架開發或者是網站初始化腳本中,用來計算網站的根目錄

 

__DIR__ 返回當前的文件路徑

 

__LINE__  返回當前的行號

在框架中,可以用來在debug時,記錄錯誤信息

 

__CLASS__ 返回當前的類名

 

__METHOD__ 返回當前的方法名

 

 

延遲綁定

注意 :static::方法名  表示調用 對象類中的方法 或者屬性

注意 一般書寫的時候public等權限修飾符在static前,增加規范可讀性

 

抽象

抽象類 :類前加 abstract 是抽象類,是抽象方法抽象類不能 new 來實例化,有抽象方法,則此類必是抽象類;抽象類,內未必有抽象方法

抽象方法 :方法前加 abstract,抽象方法 不能有方法體,所以沒有{} ; 而是直接();

子類 繼承 抽象的父類 必須 重寫父類的抽象方法!並且參數個數要一樣

//利用面向對象思想實現不同語言首頁歡迎!

//抽象類就是個模板,你們子類繼承我的類和方法自己搞自己想要弄的東西

//比如我想要開發英語語言,只要增加一個子類,不用修改父類的東西

//所以面向對象是可插拔的

 

<?php
//利用面向對象思想實現不同語言首頁歡迎!
//抽象類就是個模板,你們子類繼承我的類和方法自己搞自己想要弄的東西
//比如我想要開發英語語言,只要增加一個子類,不用修改父類的東西
//所以面向對象是可插拔的
abstract class Language { //抽象方法
    public abstract function wel();
}
class China extends Language {
    public function wel() {
        echo "歡迎!";
    }
}
class English extends Language {
    public function wel($a) {
        echo "Welcome!";
    }
}
$language = 'China';
$w = new $language(); //666
$w->wel();
?> 

說明 : 抽象類就是一個模板,我不用擔心同類的類不會做,反正你只要根據我的模板做就不會錯。從而達到兼容多種不同的情況 和 避免代碼大量的修改 和 代碼的規范(方法一致)

比如 :

公司網站要上線了,要選擇什么數據庫? 先弄個mysql開發着,到時候有問題再換也行。那么換數據庫,會不會以前的代碼又得重寫? 其實不用擔心,用抽象類!開發者,開發時,就以db抽象類來開發。不管上線時,真正用什么數據庫,我只需要再寫一份如下類(右圖)即可。所以業務邏輯層不用改,因為都實現的db抽象類。

 

接口 

(沒有括號) interface 接口名 {  }

類如果是一種事物/動物的抽象,那么 接口則是事物/動物的功能的抽象,即再把它們的功能各拆成小塊自由組合成新的物種。

以人類為例, class Human 是人的草圖而接口 是零件可以用多種零件組合出一種新特種來.

1、接口本身即是抽象的,內部聲明的方法 默認也是抽象的.不用加 abstract

2、一個類可以一次性實現多個接口.語法用 implements 實現 (把我這幾個功能實現了)

3、接口可繼承另一個接口, 用extends ;注意實現時須把繼承的接口的方

4、接口是一堆抽象方法的說明,不能加屬性

5、接口就是供組裝成類用的,封閉起來沒有意義,因此方法只能是public

<?php
/*
接口 就更加抽象了,比如一個社交網站,關於用戶的處理是核心應用。
登陸 退出 寫信 看信 招呼 更換心情
吃飯 罵人 搗亂 示愛 撩騷

這么多的方法,都是用戶的方法,可寫一個user類,全包裝起來
但是,分析用戶一次性使不了這么方法。於是分開多個類

用戶信息類:{登陸,寫信,看信,招呼,更換心情,退出}
用戶娛樂類:{登陸,罵人,搗亂,示愛,撩騷,退出}
*/
interface UserBase { //注意沒括號
    public function login($u, $p);
    public function logout(); //注意是抽象方法
    
}
interface UserMsg {
    public function wirteMsg($to, $title, $content);
    public function readMsg($from, $title);
}
interface UserFun {
    public function spit($to);
    public function showLove($to);
}
/*
作為調用者, 我不需要了解你的用戶信息類,用戶娛樂類,
我就可以知道如何調用這兩個類

因為: 這兩個類 都要實現 上述接口.
通過這個接口,就可以規范開發.

*/
class User implements UserBase {
    public function login($u, $p) {
        echo "用戶登錄";
    }
    public function logout() {
        echo "用戶注銷";
    }
}
?> 

 

包含類進來

include/require能夠包含某個php文件,但是不知道是否調用過;改進使用魔術方法__aotoload($)

__autoload() : 如果調用某個不存在的類,在報錯之前,系統會調用__autoload($n)函數,並把"類名"自動傳給__autoload函數我們自然可以在__autoload里 加載需要的類!

 

★自定義 自動加載方法

通知系統,讓系統知道--我自己寫了一個自動加載方法,用這個spl_auto_register($n)

 

 

★方法中能定義一個類,但是想要執行類里面的東西,必須先動態調用方法(直接方法名),有return也不關事

 

 

 

異常

討論:如何判斷mysql類連接是否成功? 利用 在方法里面return?

實例化后返回一個對象,無法確定是否連接成功 。 return無法干擾,仍然是返回對象

解決這種問題,用異常類 Exception

 

 

注意 @mysql_connect();  //@表示忽略此處輸出的錯誤

關閉所有的錯誤報告 : Error_reporting(0);

 

     {
         protected $conn = NULL;

         public function __construct()
         {
             $this->conn = mysql_connect('localhost','root','111');

             if (!$this->conn) //如果連接失敗了,拋出錯誤
             {
             $e = new Exception('失敗了!',9); // 
             throw $e;  //拋出異常
             }
         }
     }
    //若拋出異常,沒有接受處理則會報錯
     try  // 可能出現錯誤的代碼並嘗試捕捉錯誤信息
     {
         $my = new mysql();
     }catch(Exception $e) // 注意括號,處理錯誤
     {
             echo $e->getMessage();
            echo '錯誤代碼',$e->getCode();
            echo '錯誤文件',$e->getFile();
            echo '錯誤行',$e->getLine();//拋出錯誤的行
     }
 ?>

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM