<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                * 關鍵詞:類,類實例,對象,對象檢測 * 類的三大特性: * 封裝:把對象的屬性和方法組織在一個類(邏輯單元)里 * 繼承:以原有的類為基礎,創建一個新類,從而代碼復用的目的 * 多態:允許將子類類型的指針賦值給父類類型的指針 > 需要的數據庫 ```php CREATE TABLE `user` ( `uid` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用戶ID', `name` varchar(50) NOT NULL COMMENT '姓名', `age` smallint(3) unsigned NOT NULL COMMENT '年齡', PRIMARY KEY (`uid`) ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; INSERT INTO `user` VALUES ('1', '歐陽克', '18'); INSERT INTO `user` VALUES ('2', '老頑童', '50'); INSERT INTO `user` VALUES ('3', '黃蓉', '33'); INSERT INTO `user` VALUES ('4', '郭靖', '18'); INSERT INTO `user` VALUES ('5', '一燈大師', '80'); INSERT INTO `user` VALUES ('6', '洪七公', '79'); ``` ***** ### :-: 一、創建類 * 類不好理解,因為概念太抽象。 * 先說一個比較抽象的,比如動物是一個類,而兔子、豬、貓狗,都是動物類的實例化對象。 * 類就是一個分類,一個清單。這個類有什么,通過這個類,創建出對象。 * 對象不是憑空出來的,都是通過類創建出來的。所以咱們是先寫類,在創建對象。 ```php # 創建類 class Animal{ } # 調用類(實例化) $monkey = new Animal(); // 猴子 $rabbit = new Animal(); // 兔子 ``` >[danger] 備:類如果只能使用一次,那我們沒必須用類,每次直接寫代碼就可以了。所以類可以實例化多次(N次),次數無限制。 * 同一個類實例化出來,它們是不一樣的 ```php var_dump($monkey == $rabbit); echo '<br>'; var_dump($monkey === $rabbit); echo '<br>'; ``` * 檢測對象是否是類的實例 ```php var_dump($monkey instanceof Animal); echo '<br>'; ``` ***** ### :-: 二、類屬性 * 關鍵詞: 類屬性, 訪問限制符, 動態屬性 >[info] 在類里直接寫代碼,是錯誤的 ```php # 錯誤示例 class Animal{ echo 111; } ``` * 類 是一個類型的集合,它里面有成員的。 * 類里成員有兩種:屬性(變量)和行為(方法)。任何類,都有屬性和行為。 #### 1、**屬性(變量)** ```php class People{ $name = '楊冪'; //會報錯,必須有修飾符 $age = 31; //會報錯,必須有修飾符 // 屬性 設置了初始值 public $name = '楊冪'; public $age = 31; } # 外部訪問:需要通過訪問限定符、或修飾符 $yangmi = new People; echo $yangmi->name; ``` * 在類中聲明屬性變量時,設置它的作用域 * 作用域(修飾符):目前我們先學習public * public 公有的,類內,類外,子類都是可訪問的 * protected 受保護的,類內,子類都可以訪問 * private 私有的,只能類內訪問 >[info] 屬性重新賦值 ```php $yangmi->name = '歐陽克'; $yangmi->age = 18; echo $yangmi->name.$yangmi->age; ``` #### 2、**行為(方法)** * 關鍵詞: self, $this * 每個方法里,都帶有$this,用作調用自己類的屬性和方法 ```php class People{ // 屬性 public $name = '楊冪'; public $age = 31; // 方法,默認就是public ,不加也是 public function getInfo(){ echo '姓名:楊冪,年齡:31'; return '姓名:楊冪,年齡:31'; } // 方法 public function getInfo1(){ // self : 當前類 $obj = new self(); // 輸出對象屬性 return '姓名: ' .$obj->name .', 年齡: ' . $obj->age . '<br>'; } // 方法 public function getInfo2(){ // 因為該方法必須通過對象調用,所有沒必要在類中實例化 // 直接引用該類的實例化對象即可 // 在類中使用偽變量: "$this" 引用當前類的實例 // $this = new self(); 相當于先執行了這條語句,盡管你不需要這樣做 return '姓名: ' .$this->name .', 年齡: ' . $this->age . '<br>'; } // 方法 public function getInfo3(){ // 當前類 $obj = new People(); $obj->name = '歐陽克'; $obj->age = 18; // 輸出對象屬性 return '姓名: ' .$obj->name .', 年齡: ' . $obj->age . '<br>'; } } // 類實例化 $yangmi = new People(); echo $yangmi->getInfo(); echo $yangmi->getInfo1(); echo $yangmi->getInfo2(); echo $yangmi->getInfo3(); // 查看類中定義的對象方法: public 才會顯示出來 $methods = get_class_methods('People'); echo '<pre>'.print_r($methods,true); echo '<hr>'; ``` ***** ### :-: 三、構造方法(魔術方法) * 構造方法是類中的特殊方法,在類實例化時會被自動調用,可用來初始化對象成員 * 調用類的時候,立即執行構造方法,第一個執行的方法。方法的沒有位置的先后順序 * 構造方法: `public function __construct(){...}` ,也可以跟類名一樣的方法 ```php class People{ // 屬性 public $name; public $age; // 構造方法 public function __construct($name, $age){ echo '開始執行'; $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年齡: ' . $this->age . '<br>'; } } // 實例化 $obj = new People('楊冪',31); echo $obj->getInfo(); ``` ***** ### :-: 四、析構方法(魔術方法) * 析構方法是類中的特殊方法,在類執行完前,自動調用。可以釋放,關閉一些資源 * 構造方法: `public function __destruct(){...}` ,也可以跟類名一樣的方法 ```php class People{ // 屬性 public $name; public $age; // 構造方法 public function __construct($name, $age){ echo '開始執行'; $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年齡: ' . $this->age . '<br>'; } // 析構方法 public function __destruct(){ echo '類執行完畢,要關閉了'; } } // 實例化 $obj = new People('楊冪',31); echo $obj->getInfo(); $obj = null; // 如果沒有手動釋放,就會在最后執行析構方法 ``` >[info] 實戰:自動連接數據庫 ```php class Db{ // 連接參數 public $dsn; public $user; public $password; // 連接屬性 public $pdo; // 連接方法 public function connect(){ // 使用PDO方式管理數據庫, 連接成功則返回PDO對象,賦值給對象屬性pdo $this->pdo = new PDO($this->dsn, $this->user, $this->password); } // 希望在實例化時, 自動連接數據庫, 這個需求很常見 public function __construct($dsn, $user, $password){ // 初始化對象屬性 $this->dsn = $dsn; $this->user = $user; $this->password = $password; // 自動調用對象方法,連接數據庫 $this->connect(); } // 析構方法 public function __destruct(){ $this->pdo = null; } } // 實例化 $db = new Db('mysql:host=localhost;dbname=ouyangke', 'root', 'root'); if ($db->pdo) { echo '<h2>連接成功</h2>'; } // 讀取數據庫測試 $stmt = $db->pdo->prepare('select * from user'); $stmt->execute(); foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $user) { print_r($user); echo '<br>'; } ``` ***** ### :-: 五、類的繼承:類的第一特點 * 功能擴展, 方法重寫 * 繼承只能單集成,不能繼承多個父類 * 繼承方便擴展,維護 ```php class People{ // 對象屬性 public $name; public $age; // 構造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年齡: ' . $this->age; } } // 子類Sub1, 代碼復用 class Woman extends People{ // ... } // 實例化子類Woman, 盡管子類中無任何成員,但是它可以直接調用父類People中的全部成員 $sub1 = new Woman('楊冪', 31); echo $sub1->getInfo() . '<br>'; ``` >[info] 實現子類里的方法 ```php // 子類Woman, 增加屬性和方法,擴展父類功能 class Woman extends People{ public $wages; // 工資 // 子類的構造方法 public function __construct($name, $age, $wages){ // 調用父類的構造方法,否則還要手工把父類中的屬性初始化語句全部寫一遍 // parent:: 調用被覆寫的父類方法內容 parent::__construct($name, $age); // 只需要添加子類中的成員初始化代碼 $this->wages = $wages; } // 計算一年工資 public function total(){ return $this->wages*12; } } // 實例化子類 $sub2 = new Woman('楊冪',31,500000); echo $sub2->name . '的年薪: ' . $sub2->total() . '<br>'; ``` >[info] 子類重寫父類方法 ```php // 如果父類有這個方法,子類也用了這個方法 // 第三個子類, 繼承自Woman, 而Star又繼承自People,這就形成了多層給的繼承關系 class Star extends Woman{ // 重寫父類total()方法 public function total(){ $total = parent::total(); // 判斷工資單位 switch ($total) { case $total>100000000: $total = ($total/10000).'億'; break; case $total>10000: $total = ($total/10000).'萬'; break; default: $total = $total; break; } return $total; } } // 實例化子類 $sub3 = new Star('楊冪',31,500000); echo $sub3->name . '的年薪: ' . $sub3->total() . '<br>'; echo '<hr>'; ``` * 備注:this,parent關鍵字 * this是指向當前對象,也包括繼承的。但是會有相同的方法名,this是先找本類,在上父類 * parent是指向父類,重寫時,使用到。或者有父類和子類,有相同方法時,才使用。 ***** ### :-: 六、類的封裝:類的第二特點 * 訪問控制符, public, protected, private * public: 默認, 類內,類外,子類都可見 * protected: 類內, 子類可見, 類外不可見 * private: 類內可見, 子類, 類外不可見 >[info] 成員(變量)的封裝 ```php class Woman{ // 屬性 public $name; // 姓名 protected $age; // 年齡 private $wages; // 工資 // 構造方法 public function __construct($name, $age, $wages){ $this->name = $name; $this->age = $age; $this->wages = $wages; } } // 類實例化 $obj = new Woman('楊冪',31,500000); echo $obj->name, '<br>'; // echo $obj->age, '<br>'; // 會報錯 // echo $obj->wages, '<br>'; // 會報錯 // 繼承后訪問 class Star extends Woman{ public function info(){ echo $this->name, '<br>'; echo $this->age, '<br>'; // echo $this->wages, '<br>'; // 會報錯 } } // 類實例化 $obj1 = new Star('baby',28,400000); echo $obj1->name, '<br>'; // echo $obj->age, '<br>'; // 會報錯 // echo $obj->wages, '<br>'; // 會報錯 echo $obj1->info(); echo '<hr>'; ``` >[info] 行為(方法)的封裝 ```php class Woman{ // 屬性 public $name; // 姓名 protected $age; // 年齡 private $wages; // 工資 // 構造方法 public function __construct($name, $age, $wages){ $this->name = $name; $this->age = $age; $this->wages = $wages; } public function name(){ return '我的名字叫:'.$this->name.'<br>'; } protected function age(){ return '我的年齡是:'.$this->age.'<br>'; } private function wages(){ return '我的工資是:'.$this->wages.'<br>'; } public function all(){ echo $this->name(); echo $this->age(); echo $this->wages(); } } // 類實例化 $obj = new Woman('楊冪',31,500000); echo $obj->name(); //echo $obj->age(); // 會報錯 //echo $obj->wages(); // 會報錯 echo $obj->all(); class Star extends Woman{ public function info(){ echo $this->name(); echo $this->age(); // echo $this->wages(); //私有的會報錯 } public function a(){ echo $this->all(); } } // 類實例化 $obj1 = new Star('baby',28,400000); echo $obj1->a(); echo '<hr>'; ``` ***** * 類的文件起名: * 有描述意義,比如:女人woman * 用二級命名,比如:女人woman.class.php, 二級命名是告訴程序員,不直接運行的文件。 * 一般一個文件,只保存一個類,所以不會在類的文件里,調用本類。 * 都是在外部調用。新建個文件,調用這個類。include '類文件' * include 'woman.class.php' ***** ### :-: 七、類屬性與類方法(靜態成員) * 類屬性: 靜態屬性 * 類方法: 靜態方法 * 靜態成員屬于類,而不屬于對象(重點) * 靜態成員不需要通過對象訪問,所以不必實例化 * 使用`static`關鍵字定義 * 類外使用類名訪問,類內使用`self`訪問 * 類外部, 類屬性不能用實例訪問,但類方法可以 ```php class People{ // 屬性 public $name; // 屬性 public $age; // 屬性: 靜態屬性 public static $country = '中國'; // 構造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; // $this->country = $country; // 會報錯 // 盡管可以在構造方法中初始化靜態屬性,但不建議這樣做,否則靜態屬性,無法在對象之間共享 } // 對象方法 public function getInfo1(){ // 這個方法可以用對象訪問,方法中訪問了靜態屬性,實現了類屬性在對象中的共享 // return $this->name . '年齡是: ' . $this->age. '國家是:' . $this->country; // 這樣會報錯 return $this->name . '年齡是: ' . $this->age. '國家是:' . self::$country; } // 類方法: 靜態方法 public static function getInfo2(){ // 靜態方法是類方法, 不能用對象調用,所以內部也不允許使用對象引用$this // 如果靜態方法中,一定要用到對象屬性或方法,可以用參數傳入 return $this->name . '年齡是: ' . $this->age . '國家是:' . self::$country; } // 靜態方法: 以方法傳參方式調用對象屬性/方法 public static function getInfo3($name,$age){ // return $this->name; // 會報錯,在靜態方法里,不能訪問非靜態成員 // 可以用self調用,也可以用本類名調用。 最好在本類用self,在外部用類名 return $name . '年齡是: ' . $age . '國家是:' . Demo1::$country; } } $obj = new People('范冰冰',33); echo $obj->name, '<br>'; echo $obj->age, '<br>'; // echo $obj->country, '<br>'; //會報錯 echo People::$country; // 應該以這種方式訪問靜態屬性 echo '<br>'; echo $obj->getInfo1(), '<br>'; // echo $obj->getInfo2(), '<br>'; // 會報錯 // echo People::getInfo2(), '<br>'; // 會報錯 echo People::getInfo3($obj->name,$obj->age); echo '<br>'; // 對象不能訪問靜態屬性,但是可以訪問靜態方法 echo $obj->getInfo3($obj->name,$obj->age); // 靜態成員可以重新賦值。在創建很多對象,值不會因為創建的對象改變。 People::$country = 'china'; $obj1 = new People('楊冪',31); echo People::$country; echo '<hr>'; ``` * 之前,將類做為對象的模板, 訪問類中的成員,必須先將類實例化,通過對象訪問 * 面向對象編程,實際上操作都是對象,而類,僅做為生成對象的代碼模板而存在 * 而實際情況卻并非總是如此,試想一下,以下的二種場景: * 如果一個對象,我們僅僅只用一次,還有必要創建對象嗎, 直接將類變為對象,豈不是更方便? * 如果多個對象之間, 需要共享一些屬性和方法, 而他們必須通過一個個獨立對象調用的,無法共享,怎么辦? * 靜態可以公用,只會在內存中,生成一份。 * 靜態只有在程序執行完,才會被釋放。 * 能用靜態,就多用靜態,靜態效率高 * 以上情況,將屬性和方法直接定義在類中, 直接用類調用, 就可以解決 ***** ### :-: 八、類常量 * 類常量也類屬性一樣,也是屬于類的, 必須用類訪問,不能用對象訪問 * 類常量與類屬性的區別是: 類常量不允許修改,而類屬性可以修改 * 類常量與普通常量的命名規則是一致的, 推薦使用大寫字母或大寫字母+下劃線 * 類常量不需要設置訪問限制符,默認行為與`public`是一樣的 ```php define('COUNTRY','中國'); class People{ // 類常量也類屬性一樣,也是屬于類的, 必須用類訪問,不能用對象訪問 const COUNTRY = '中國'; // 類常量與類屬性的區別是: 類常量不允許修改,而類屬性可以修改 public static $sex = '女'; private $name; public function __construct($name){ $this->name = $name; } public function getInfo(){ // 類常量在類的內部,訪問方式與類屬性是一樣的 return $this->name.'的性別是:' . self::$sex.',國籍是: ' . self::COUNTRY; } } $obj = new People('劉詩詩'); // 訪問類屬性 echo People::$sex, '<br>'; // 訪問類常量 echo People::COUNTRY, '<br>'; // 訪問對象方法: 該方法又訪問了類屬性與類常量 echo $obj->getInfo(); echo '<hr>'; // 修改類屬性 People::$sex = '保密'; // 修改類常量: 報錯 //People::COUNTRY = '美國'; // 可以看到類屬性:$sex發生了變化 echo $obj->getInfo(); echo '<hr>'; ``` ***** ### :-: 九、屬性重載 * 重載: 動態的創建屬性和方法 * 當訪問未定義或不可見的屬性/方法時, 重載方法會自動調用 * "當訪問未定義或不可見", 統稱為: "不可訪問" * PHP中的重載,是通過"魔術方法"實現 * "魔術方法"是特指客戶端不能訪問,而只能是系統根據一定條件自動調用 * 所有重載方法必須聲明為: `public` * 重載方法 * `__get($name)`: 當獲取未定義可不見屬性時觸發,需要一個參數 * `__set($name, $value)` :當給未定義可不見屬性賦值時觸發,需要兩個參數 * `__isset($name)`: 當檢測未定義可不見屬性時觸發 * `__unset($name)`: 當注銷未定義可不見屬性時觸發 * 魔術方法,可以給變量賦值。它的作用是可以進行賦值判斷,如果是共有的,可以隨便賦值。直接復制不能判斷,用\_\_get,\_\_set可以判斷一些不太可能的值。比如年齡,不可能會超過200歲。比如女朋友,不可能多個。 ```php class People{ private $name; private $age; protected $country = '中國'; // public $country = '中國'; // 構造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; } // __get($name):當獲取未定義可不見屬性時觸發 // $name 是屬性名 public function __get($name){ if ($name === 'country') { // 僅允許name=='admin'的用戶可以查看country字段內容 return ($this->name === 'admin') ? $this->$name : '無權查看';; } return $this->$name; } // __set($name, $value):當給未定義可不見屬性賦值時觸發 public function __set($name, $value){ // 直接返回, 極少這樣做,這樣做相當于把類屬性直接設置為:public // $this->$name = $value; // 添加過濾機制 if ($name === 'age') { return $this->name === 'admin' ? $this->$name = $value : '無權修改'; } return $this->$name = $value; } // __isset($name): 當檢測未定義可不見屬性時 public function __isset($name){ if ($this->name === 'admin') { if (isset($this->$name)){ echo '存在該屬性'; } else { echo '沒有該屬性'; } } else { echo '無權檢測'; } } //__unset($name): 當注銷未定義可不見屬性時觸發 public function __unset($name){ if ($this->name === 'admin') { unset($this->$name); } else { echo '無法刪除'; } } } $obj = new People('迪麗熱巴', 26); echo $obj->name, '<br>'; echo $obj->country, '<br>'; // 怎么才能查看 country, 只能用'admin'來實例化 $obj = new People('admin', 50); echo $obj->country, '<br>'; // 直接修改 age, 類中沒有__set()會報錯 $obj->age = 80; // 查看age字段值 echo $obj->age, '<br>'; // 檢測是否存在age字段 isset($obj->age); echo '<br>'; // 刪除salary屬性 unset($obj->age); echo '<br>'; isset($obj->age); echo '<hr>'; ``` ***** ### :-: 十、方法重載 * `__call()`: 訪問未定義的對象方法時會自動調用它 * `__callStatic()`: 訪問未定義的靜態類方法時會自動調用它 ```php class People{ // __call(): 訪問不存在/不可見對象方法時觸發,有兩個參數,第一個是方法名,第二個方法的參數 public function __call($name, $arguments){ return '方法名: '.$name.'<br>方法參數列表: ' . '<pre>'.print_r($arguments, true).'不存在'; } // __callStatic(): 訪問不存在/不可見的類方法(靜態)方法時觸發 public static function __callStatic($name, $arguments){ return '方法名: '.$name.'<br>方法參數列表: ' . '<pre>'.print_r($arguments, true).'不存在'; } } $obj = new People(); // 訪問不存在或無權訪問的對象方法 echo $obj->getInfo1(10,20,30); echo '<hr>'; // 訪問不存在或無權訪問的靜態類方法 echo Demo4::getInfo2('html','css', 'javascript'); echo '<hr>'; ``` ***** ### :-: 十一、小案例 * call_user_func($callback[,$parameter...]): 以函數參數的方式,執行一個函數,其實就是以回調的方式執行函數 * call_user_func_array($callback,$array): 功能與call\_user\_func()相同, 僅僅是參數以數組形式提供 ```php function sum($a, $b) { return $a . ' + ' . $b . ' = ' . ($a+$b); } // 正常函數調用 echo sum(20, 40); echo '<br>'; // 以回調的方式執行該函數 echo call_user_func('sum', 50, 20); echo '<br>'; // call_user_func_array(), 第二個參數是數組格式,不能省略 echo call_user_func_array('sum', [30, 80]); echo '<hr>'; ``` ```php // 現在換個思路, 將函數放在一個類中, 再來調用這個方法/函數 class Test1{ // 對象方法 public function sum($a, $b){ return $a . ' + ' . $b . ' = ' . ($a+$b); } } // 如果以回調方式執行對象方法呢? $obj = new Test1(); echo call_user_func([$obj,'sum'], 50, 20); echo '<br>'; // 僅以call_user_func_array()舉例, call_user_func()原理一樣 echo call_user_func_array([$obj,'sum'], [10,30]); echo '<br>'; // 如果僅調用一次,可以簡化一下對象創建方式 echo call_user_func_array([new Test1(),'sum'], [15,35]); echo '<hr>'; ``` ```php // 如果是一個靜態方法,如果調用呢? class Test2{ // 對象方法 (乘法運算) public static function mul($a, $b){ return $a . ' * ' . $b . ' = ' . ($a*$b); } } // 直接將類名與方法寫在一個字符串即可 echo call_user_func_array('Test2::mul', [10,30]); echo '<br>'; // 將類名與類方法分開,放在一個數組中 echo call_user_func_array(['Test2','mul'], [10,30]); echo '<br>'; echo '類名是: '. Test2::class; // 返回一個類名字符串 echo '<br>'; // 所以這樣寫,也是正確的 echo call_user_func_array([Test2::class,'mul'], [10,30]); ``` > 下面是一個sql語句類的案例 * 類方法的跨類調用的實現:方法重載的應用,數據庫查詢的鏈式操作 * 鏈式調用的原理分析:以模擬ThinkPHP5.1框架中的數據庫查詢構造器為案例,來演示方法重載的精妙之處 ```php require 'query.php'; class Db { // 數據庫連接對象 protected static $pdo = null; // 數據庫連接方法, 每次查詢時再連接, 實現真正的惰性連接,節省系統開銷 public static function connection(){ // 為簡化,這里直接使用字面量參數連接數據庫,真實項目中應該將參數放在配置文件中 self::$pdo = new PDO('mysql:host=localhost;dbname=ouyangke','root','root'); } // 這是查詢類操作的入口, 通過靜態魔術方法進行跳轉,實現對象方法的跨類調用 public static function __callStatic($name, $arguments){ // 創建pdo對象,并連接數據庫 self::connection(); // 實例化查詢類,將連接對象做為參數 $query = new query(self::$pdo); // 執行查詢類Query中的對象方法, 注意參數是數組,我只需要第一個參數:表名, 所以加了索引鍵名 return call_user_func_array([$query,$name],[$arguments[0]]); } } // 客戶端的鏈式調用 // 以Db類做入整數數據庫操作的入口, SQL語句的各個部分用對象方法提供 // 鏈式操作是現代PHP框架的基礎,非常有用 $users = Db::table('user') ->field('uid,name,age') ->where('uid > 1') ->limit(5) ->select(); // 遍歷查詢結果 foreach ($users as $user) { print_r($user); echo '<br>'; } ``` > query.php ```php <?php // 數據庫查詢類 class query { // 連接對象 public $pdo = null; // 數據表名 public $table = ''; // 字段列表 public $field = ''; // 查詢條件 public $where = ''; // 顯示數量 public $limit = 0; // 構造方法,初始化連接對象 public function __construct($pdo) { // 連接對象是對象方法的共享屬性 $this->pdo = $pdo; } // 調用表名 public function table($tablName) { $this->table = $tablName; // 返回當前對象,便于鏈式調用該對象的其它方法 return $this; } // 設置查詢字段 public function field($fields) { $this->field = $fields; return $this; } // 設置查詢條件 public function where($where) { $this->where = $where; return $this; } // 設置顯示數量 public function limit($limit) { $this->limit = $limit; return $this; } // 創建SQL查詢語句對象,并返回查詢結果 public function select() { // 查詢條件分開設置, 可以確保鏈式方法獨立 $fields = empty($this->field) ? '*' : $this->field; $where = empty($this->where) ? '' : ' WHERE '.$this->where; $limit = empty($this->limit) ? '' : ' LIMIT '.$this->limit; // 接裝SQL語句 $sql = 'SELECT '.$fields.' FROM '.$this->table. $where . $limit; // 預處理查詢 $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } } ``` ***** ### :-: 十二、自動加載 * `spl_autoload_register(callback)`: 通過回調自動加載外部文件 * `__DIR__`魔術常量 ```php // 查看當前腳本所在的目錄 echo __DIR__, '<br>'; include __DIR__ . '/inc/Test1.php'; include __DIR__ . '/inc/Test2.php'; include __DIR__ . '/inc/Test3.php'; # 如果當前腳本使用了幾十上百這樣的類, 上面的方式就很不人性 # 使用下面的自動加載機制, 會根據客戶端調用的類, 自動進行加載,效率高, 不出錯 ``` ```php // php標準函數庫中提供了一個自動加載文件的注冊函數,可以實現這個功能 // 這個函數,在當前腳本引用一個未加載的文件時, 會自動調用它的回調方法來加載這個文件 spl_autoload_register(function ($class){ // include __DIR__ . '/inc/Test1.php'; // 將include中的類名Test1用變量替換掉,這樣就實現了最簡單的自動加載 // 后面我們會使用命名空間來完善這個函數,目前大家先理解到這里即可 include __DIR__ . '/inc/'.$class.'.php'; }); $test1 = new Test1(); echo $test1->get(), '<br>'; $test1 = new Test2(); echo $test1->get(), '<br>'; $test1 = new Test3(); echo $test1->get(), '<br>'; echo '<hr>'; ``` >[info] Test1.php、Test2.php、Test3.php 文件 ```php <?php namespace inc; class Test1{ public static function get(){ return __CLASS__ . ' 類, 加載成功~~'; } } ``` ***** ### :-: 十三、抽象類 * `abstract`: 定義抽象方法/抽象類 * 類中只要有一個抽象方法, 該類就應該聲明為抽象類 * 抽象類只能被繼承,不能實例化,并且抽象方法必須在子類實現 * 實現抽象方法的子類方法可見性不能低于抽象方法原定義 * 抽象方法是public, 子類方法只能是public * 抽象方法是protected, 子類方法只能是protected/public > 一個抽象類必須被擴展為一個特定的類,我們才能創建類實例,使用類中功能 ```php abstract class a{ public $name; public function __construct($name){ $this->name = $name; } // 不管有多少個普通方法,只要有一個抽象方法,就是抽象類 public function af(){ echo $this->name; } // 抽象方法不能有內容,里面不能有代碼,{}:不能有 abstract public function aff(); } // 抽象類不能實例化,不能new,只能繼承 // 我們就用b類,繼承 a抽象類 class b extends a{ // b類 繼承 a抽象類后:必須把a抽象類 ,里面的抽象方法,重新寫一遍(實現) public function aff(){ echo $this->name; } } // 實現后,我們可以調用子類,進行實例化,然后調用成員方法和成員變量。 $a = new b('歐陽克'); // 為什么抽象類里的af方法能調用呢,因為它是普通方法。 $a->af(); echo '<br/>'; // 這里的方法為什么能調用呢? 因為b類,繼承了a抽象類的方法后:實現成為普通類。 $a->aff(); ``` * 在實際開發過程中, 通常并不會直接使用一個父類/超類,而是在父類中定義一些方法聲明 * 并且確信這個方法肯定是會被子類重寫的, 父類中沒必要實現,只要給一個方法編寫規范即可 * 這個規范包括方法的名稱, 參數列表等,具體實現就完全交給子類去完成了 * 相當于公司的部門主管, 接受到老板的任務, 只把屬于自己的部分做了, 其它部分, 設置一個標準交給下屬去完成 ```php abstract class Person{ protected $name; protected function __construct($name='peter zhu'){ $this->name = $name; } // 該方法不需要重寫, 可以通過子類對象訪問,應該設置為public public function getName(){ return $this->name; } // 修改屬性方法,設置為抽象方法,交給子類實現 abstract protected function setName($value); } // 當子類繼承 抽象父類,普通的方法,可以直接使用,抽象方法,必須重新實現。 class Stu extends Person{ // 注意: 構造方法不會自動繼承, 必須手動重寫 public function __construct($name='peter zhu'){ parent::__construct($name); } // 1,它的父類,有這個抽象方法,這里必須重新寫,帶著具體的代碼。 // 2,類實例化后,調用這個方法,就是直接調用這個方法,跟抽象方法沒關系。 public function setName($value){ $this->name = $value; } } $stu = new Stu('豬哥'); echo 'php中文網創始人: ' . $stu->getName() . '<br>'; // 調用子類的重寫的抽象方法setName(),來設置屬性 $stu->setName('滅絕師太'); // 3,用setName傳值后,值給到父抽象類里的$name,用父抽象類的getName方法可以輸出傳值 echo 'php中文網前端講師: ' . $stu->getName() . '<br>'; echo '<hr>'; ``` * 類中只要有一個成員設置為抽象,該類就必須設置抽象類 * 一個類一旦被設置為抽象類,就具備了二個特點: * 不能實例化 * 類中抽象方法,在子類中必須實現(全部),就是子類必須有父類的抽象方法 * 注意: * 屬性設置為抽象無意義, 抽象僅針對方法,類 * 子類的成員可見性必須等于或高于所繼承的抽象類成員可見性,例如抽象類是proteced,子類可以是protected/pulic * 子類重寫的抽象方法可見性,究竟用protected/pulic, 要看這個子類是最終被客戶端訪問,如果是就public,如果不是protected * 級別: * public 級別最高: A * protected 級別中等: B * private 級別最低: C ***** ### :-: 十三、接口 * `interface`: 指定某個類必須實現的方法,但不需要定義方法的具體實現過程 * 接口中僅允許出現: 方法與常量 * 接口的方法可見性必須是: public * 接口的方法體必須是空的 * 接口是類的代碼模板, 可以像類一樣有父子繼承關系,例如父接口, 子接口 * `implements`: 類實現接口的關鍵字 * 如果僅是部分實現接口中的方法, 請用一個抽象類來實現它 * 接口中的方法,必須全是抽象方法 * 抽象和接口區別: * 抽象可以有普通方法,成員變量。 * 接口不可以有普通方法,不可以有成員變量。 ```php interface iVehicle{ const COUNTRY = '中國'; // 驅動方式: 汽車, 新能源 public function setFuel($fuel); // 用途 public function setPurpose($purpose); } // Car 類 實現了接口: iVehicle,關鍵詞:implements // 抽象類 實現接口: iVehicle,關鍵詞:implements // 接口 可以 繼承接口:extends // 類 可以 同時 繼承 和實現(先繼承,在實現) // 可以實現多個接口,用逗號隔開 class Car implements iVehicle{ public $fuel; public $purpose; // 構造方法 public function __construct($fuel='汽油', $purpose='家用'){ $this->fuel = $fuel; $this->purpose = $purpose; } // 必須實現的接口方法 public function setFuel($fuel){ $this->fuel = $fuel; } // 必須實現的接口方法 public function setPurpose($purpose){ $this->purpose = $purpose; } // 類中自定義的對象方法 public function getInfo(){ return $this->fuel . $this->purpose . '車 <br>'; } } // 客戶端代碼 $car = new Car(); echo $car->getInfo(); $car->setFuel('新能源'); $car->setPurpose('公交'); echo $car->getInfo(); echo '<hr>'; ``` > 如果暫時只能實現接口中的部分方法, 可以用一個抽象來實現這個接口 ```php interface iVehicle{ const COUNTRY = '中國'; // 驅動方式: 汽車, 新能源 public function setFuel($fuel); // 用途 public function setPurpose($purpose); } abstract class Auto implements iVehicle{ public $fuel; // 只實現接口中的setFuel()方法, 另一個方法并未實現 public function setFuel($fuel){ $this->fuel = $fuel; } } // 再創建一個類,來繼承擴展這個抽象類 Auto class Car1 extends Auto{ public $purpose; // 構造方法 public function __construct($fuel='汽油', $purpose='家用'){ $this->fuel = $fuel; $this->purpose = $purpose; } // 這個方法原來在接口中聲明的,在它繼承的抽象類中并沒有聲明 public function setPurpose($purpose){ $this->purpose = $purpose; } // 自定義的方法 public function getInfo(){ return $this->fuel . $this->purpose . '車 <br>'; } } // 客戶端代碼 $car1 = new Car1(); echo $car1->getInfo(); $car1->setFuel('天然氣'); $car1->setPurpose('家用'); echo $car1->getInfo(); ``` * 總結: * 如果不能將接口中方法全部實現就用抽象類來實現它 * 否則,就必須全部把接口中方法全部實現 ***** ### :-: 十四、接口按實戰案例 ```php // 定義一個接口,實現數據庫常用操作:增刪改查 interface iCurd { // 增加數據 public function create($data); // 讀取數據 public function read(); // 更新數據 public function update($data, $where); // 刪除數據 public function delete($where); } // 創建Db類, 實現iCurd接口,完成基本的數據庫操作 class Db implements iCurd{ //數據庫的連接對象 protected $pdo = null; // 數據表名 protected $table; // 構造方法: 連接數據庫,并設置默認數據表名稱 public function __construct($dsn, $user, $password, $table='staff'){ $this->pdo = new PDO($dsn, $user, $password); $this->table = $table; } // 讀取 public function read($fields='*', $where='', $limit='0, 5'){ // 設置查詢條件 $where = empty($where) ? '' : ' WHERE ' . $where; // 設置顯示數量 $limit = ' LIMIT ' . $limit; // 預處理查詢操作 $sql = 'SELECT '.$fields.' FROM '.$this->table.$where.$limit; $stmt = $this->pdo->prepare($sql); $stmt->execute(); // 返回二維數組表示的查詢結果集 return $stmt->fetchAll(PDO::FETCH_ASSOC); } // 新增, 參數是數組: 新記錄的鍵值對 public function create($data){ // 字段列表 $fields = ' (name,age,sex,position,mobile,hiredate)'; // 值列表 $values = '(:name,:age,:sex,:position,:mobile,:hiredate)'; // 創建SQL語句 $sql = 'INSERT INTO '.$this->table.$fields.' VALUES '.$values; // 預處理執行新增操作 $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回新增數量, 新增記錄的ID組成的數組 return [ 'count'=>$stmt->rowCount(), 'id'=>$this->pdo->lastInsertId() ]; } // 更新, 為了數據安全, 不允許無條件更新 public function update($data, $where){ // 難點在于SET 參數的處理上,利用傳入的$data數組,進行拆裝 // 獲取數組的鍵名組成的數組 $keyArr = array_keys($data); $set = ''; // 遍歷鍵名表示的字段列表,拼裝預處理需要的sql語句,注意占符符的表示 foreach ($keyArr as $value) { $set .= $value . ' = :' .$value. ', '; } // 去掉最后一個逗號, 注意每個逗號后有一個空格,去除時也要帶上這個空格 $set = rtrim($set,', '); // 預處理執行更新操作 $sql = 'UPDATE '.$this->table.' SET '.$set .' WHERE ' .$where; $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回被更新的記錄數量 return $stmt->rowCount(); } // 刪除: 與更新一樣, 這也是危險的寫操作, 不允許無條件刪除 public function delete($where){ // 預處理執行刪除操作 $sql = 'DELETE FROM '.$this->table.' WHERE '.$where; $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->rowCount(); } } // 客戶端的測試代碼 // 實例化Db類 $dsn = 'mysql:host=localhost;dbname=ouyangke'; $user = 'root'; $password = 'root'; $db = new Db($dsn, $user, $password); // 遍歷讀取 foreach ($db->read() as $item) { print_r($item); echo '<br>'; } echo '<hr>'; // 新增數據 $data = [ 'name'=>'郭靖', 'age'=>30, 'sex'=>1, 'position'=>'金刀駙馬', 'mobile'=>'13666668888', 'hiredate'=>time() ]; $res = $db->create($data); echo '成功新增'.$res['count'].'條記錄,最新記錄的主鍵ID是: '.$res['id']; echo '<hr>'; // 更新記錄 $data = [ 'age' => 5, 'position'=>'抗金英雄' ]; $where = 'id = 5'; echo '成功更新了: ' .$db->update($data, $where). ' 條記錄'; echo '<hr>'; // 刪除記錄 $where = 'id = 5'; echo '成功更新了: ' .$db->delete($where). ' 條記錄'; ``` ***** ### :-: 十五、后期靜態綁定 * 后期靜態綁定,也叫"延遲靜態綁定" * 這個技術應用在靜態繼承的上下文環境中,用于動態調用被重寫的方法 * 調用被重寫的靜態方法使用關鍵字: `static` 加上"范圍解析符"`::` * `::` 范圍解析符的使用場景 * 訪問類方法與類常量 * 訪問被重寫的對象或類方法 * static關鍵字用來調用重寫方法的時候,可以動態的綁定當前調用的類 ```php class A{ public static function who(){ echo 111; } public function test(){ // self::who(); // 猜一下,是調用它自己的who,還是子類的who呢? // 那么如何在這種靜態繼承的上下文環境中, 靜態調用類中方法的時候,正確識別調用者呢? // 可以將self 關鍵字改為: static , // 注意: static 除了可以用在靜態方法中, 也可以用在普通對象方法中 static::who(); } } // B繼承了A,重寫A類里面的who方法。 class B extends A{ public static function who(){ echo 222; } } $a = new B(); echo $a->test(); ``` >[info] 表格表達類相關的關鍵詞 **關鍵詞** | **類外聲明** | **聲明類** | **聲明屬性** | **聲明方法** | **解釋** --- | --- | --- | --- | --- | --- const | √ | | √ | | 定義類常量 extends | | √ | | | 擴展類,用一個類去擴展它的父類 public | | | √ | √ | 公用屬性或方法 protected | | | √ | √ | 私有屬性或方法 private | | | √ | √ | 受保護的屬性或方法 abstract | | √ | √ | | 抽象類或方法 final | | √ | | √ | 類不能被繼承 interface | | √ | | | 創建接口 implements | | √ | | | 實現接口 parent:: | | | | | 訪問父類 $this-> | | | | | 訪問本類 self:: | | | | | 訪問靜態 static:: | | | | | 后期靜態綁定 namespace | √ | | | | 創建命名空間
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看