PHP OOP

PHP 使用了一段時間, 從對OOP的不瞭解, 再到使用, 以爲挺好, 特寫下php

看面向對象, 我是看的這個雞啄米的c++, http://www.jizhuomi.com/softw...html

OOP並非爲了面向對象而面向對象, 而是爲了達到代碼的重用性靈活性擴展性c++

對象和類

從先有對象纔有人類, 這個來講, 有點不合理的合理shell

類:具備相同屬性的一組對象的集合
對象:類實例化以後就是對象
看下通常的類的定義編程

<?php
class Person{
    // 成員變量
    private $name;
    private $sex;
    private $age;
    // 構造函數
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    // 析構函數
    function __destruct(){
        echo "byebye\n";
    }
    // 成員方法
    function eat(){
        echo "my name is ". $this->name;
    }
    function sleep(){
        echo "i am sleeping";
    }
}
// 類的實例化
$jaime = new Person("jaime", "man", 24);
$jaime->eat();

?>

保存爲index.php, 在命令窗口輸入api

$ php index.php
my name is jaime
byebye

若是函數

$jaime = new Person("jaime", "man", 24);

改成this

$jaime = new Person("jaime", "man");

則會觸發異常, 會有如下的消息出來, 包括錯誤信息, 錯誤行數, 和堆棧信息.net

$ php index.php

Fatal error: Uncaught exception 'Exception' with message 'must set name , sex, age' in E:\net\index.php on line 15

Exception: must set name , sex, age in E:\net\index.php on line 15

Call Stack:
    0.0025     242440   1. {main}() E:\net\index.php:0
    0.0025     243016   2. Person->__construct() E:\net\index.php:30

對象和內存

說點理論上的東西吧,指針

內存的分類:

堆(heap): 不可直接存取, 存儲佔有空間很大的數據類型的數據

棧(stack): 能夠直接存取, 存儲佔用相同空間長度而且佔用空間小的數據, 如存放局部變量,函數參數,當前狀態,函數調用信息等

$jaime = new Person("jaime", "man", 24);

$jaime是存放在棧內存裏面的引用變量, 即存儲在堆中對象的首地址, 一個指針

new Person 實例化出來的對象是存放在堆內存裏面的, 是真正的對象實例

對象和成員

變量,方法(內部成員函數)的前綴:

private: 私有成員

public:  公有成員(外部接口),沒有加修飾, 默認就是public

protected: 保護型成員, 繼承的類能夠調用

訪問private修飾的變量

Fatal error: Cannot access private property Person::$name in E:\net\index.php on line 36

若是想訪問private, protected修飾的成員:

  1. 把private改成public

  2. 使用__get(), ___set()魔術方法, 可是仍是寫出代碼來看看根據實際狀況使用

<?php
class Person{
    private $name;
    private $sex;
    private $age;
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    function __destruct(){
        echo "byebye\n";
    }

    function eat(){
        echo "my name is ". $this->name."\n";
    }
    function sleep(){
        echo "i am sleeping\n";
    }

    function __get($property_name){
        $access_array = ['age','name'];// 只容許訪問age,name兩個私有成員
        if(in_array($property_name, $access_array)){
            return ($this->$property_name);
        }
        else{
            return NULL;
        }
    }
    function __set($property_name, $value){
        $access_array = ['age'];// 只容許訪問age這個私有成員
        if(in_array($property_name, $access_array)){
            $this->$property_name = $value;
        }
    }

}

$jaime = new Person("jaime", "man", 24);
$jaime->eat();
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
echo ($jaime->sex === NULL)? "NULL":$jaime->sex;
$jaime->age = 80;
echo "\n";
echo ($jaime->age === NULL)? "NULL":$jaime->age;
echo "\n";
$jaime->name = "lll";
echo ($jaime->name === NULL)? "NULL":$jaime->name;
echo "\n";
?>

執行結果以下

$ php index.php
my name is jaime
24
NULL
80
jaime
byebye

類的繼承

<?php
class Person{
    private $name;
    private $sex;
    private $age;
    function __construct($name="",$sex="",$age=""){
        if($name===""||$sex===""||$age===""){
            throw new Exception("must set name , sex, age");
        }
        $this->name = $name;
        $this->age  = $age;
        $this->sex  = $sex;
    }
    function __destruct(){
        echo "byebye\n";
    }

    function hello(){
        echo "my name is ". $this->name."\n";
    }
    function sleep(){
        echo "i am sleeping\n";
    }
}


class Student extends Person
{
    private $school;

    function __construct($name, $sex, $age, $school)
    {
        // 調用父類方法, 構造函數
        parent::__construct($name, $sex, $age);
        $this->school = $school;
    }
    // 重載了父類方法
    function sleep(){
        echo "afternoon sleep\n";
        // 調用父類方法
        parent::sleep();
    }
}

$jaime = new Student("jaime", "man", 24,"zh");
$jaime->hello();
$jaime->sleep();
?>

執行後輸出

$ php index.php
my name is jaime
afternoon sleep
i am sleeping

byebye

調用父類的方法須要用parent

靜態成員和常量

no bb, show code

<?php
class Person
{
    // 靜態成員屬性
    public static $contry = "China";
    public static function say(){
        // 靜態成員方法, 經過self訪問其它靜態成員
        // 類裏面的靜態方法只能訪問類的靜態的屬性
        echo "I live in ".self::$contry."\n";
    }
    public function show(){
        echo "xxx".self::$contry."\n";
    }
}
// 輸出靜態屬性
echo Person::$contry."\n";
// 調用靜態方法, 外部調用用類名::靜態方法
Person::say();
// 給靜態屬性從新賦值
Person::$contry = "American";
Person::say();
(new Person())->show();
?>

結果

$ php is.php
China
 en
I live in China
I live in American
xxxAmerican en

類的靜態變量,相似於全局變量,可以被全部類的實例共享,類的靜態方法也是同樣的,相似於全局函數, 靜態成員被這個類的每一個實例對象所共享

訪問靜態方法訪問靜態成員不能用$this, 須要用self

$this表示了此方法的對象

'self'表示此靜態方法所在的類, self::成員

抽象方法和抽象類

什麼叫抽象?不具體的就叫抽象! so

抽象方法 : 類裏面沒有具體方法體的方法(其實就是不具體的方法)

抽象類: 含有抽象方法的類,

抽象類不能實例化會報錯"Cannot instantiate abstract class <classname>", 有點像C裏面的函數聲明, 僅僅只是一個聲明

<?php
abstract class AbstractClass{
    // 抽象類裏面能夠有不是抽象的成員
    public $variable;
    // 抽象方法
    abstract function fun1();
    abstract function fun2();

    function fun3{
        echo "我是抽象類中的非抽象方法";
    }
}
class demo0 extends AbstractClass{
    // 子類必須把父類中的抽象方法所有都實現, 不然子類中還存在抽象方法,還是抽象類
    function fun1(){
        echo "call ".__FUNCTION__."\n";
    }
    function fun2(){
        echo "call ".__FUNCTION__."\n";
    }
}
// 我這裏是想不出名字, 不建議這樣作, 由於demo0實例化了3次
(new demo0())->fun1();
(new demo0())->fun2();
(new demo0())->fun3();
?>

接口interface

什麼是接口?

若是一個內裏面全部的方法都是抽象方法, 咱們能夠把聲明方式換爲接口

接口是一種特殊的抽象類, 接口不能包含成員的任何代碼,只定義成員身。接口成員的具體代碼由實現接口的類提供

<?php
interface One{
    // 定義常量
    const con = "xonst";
    // 定義抽象方法, 不用加abstract, 由於都是abstract
    function fun1();
    function fun2();
}
?>

接口的繼承

<?php
interface Two extends One{
    function fun3();
    function fun4();
}
?>

接口的實現

<?php
interface One{
    // 定義常量
    const con = "xonst";
    // 定義抽象方法, 不用加abstract, 由於都是abstract
    function fun1();
    function fun2();
}

interface Two extends One{
    function fun3();
    function fun4();
}
// 使用「implements」這個關鍵字去實現接口中的抽象方法
class demo implements Two
{
    function fun1() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun2() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun3() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun4() {
        echo "call ".__FUNCTION__."\n";
    }
}

(new demo())->fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>

一個類實現多個接口

一我的要遵照的法律不止一步吧, 因此see code

<?php
interface One{
    // 定義常量
    const con = "xonst";
    // 定義抽象方法, 不用加abstract, 由於都是abstract
    function fun1();
    function fun2();
}

interface Two{
    function fun3();
    function fun4();
}
// 注意這裏
class demo implements One, Two
{
    function fun1() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun2() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun3() {
        echo "call ".__FUNCTION__."\n";
    }
    function fun4() {
        echo "call ".__FUNCTION__."\n";
    }
}

(new demo())->fun1();
(new demo())->fun2();
(new demo())->fun3();
(new demo())->fun4();
?>

你娶了你老婆你得對她的家人負責吧, 就像下面

// 使用extends繼承一個類,使用implements實現多個接口
class demo extend AbstractClass implements One, Two{
    ......
    // 全部接口中的方法都要實現才能夠實例化對象
}

反射Reflection

需求: 導出或提取出關於類、方法、屬性、參數等的詳細信息, 甚至是判斷某個方法是否存在
這裏我不作多說, 看我在實際的項目中的實際應用,
這是一個API的入口處理函數, 若是存在這個方法就執行並返回結果, 不存在就拋出異常,
由於接口函數是不斷增長甚至是變化的, 使用反射做爲api的入口可讓你的具體的api函數變化了入口也不用改

try {
    // 使用工廠方法實例化具體的接口
    $instance = new \Api\Library\ApiFactory($module, $server, $this->params);
    // 反射方法
    $action   = new \ReflectionMethod($instance->instance, $method);
    // 判斷方法的類型
    if (!$action->isPublic() || $action->isStatic()) throw new \ReflectionException();
    // 驗證api參數
    $validator = new \Api\Library\ApiValidator();
    $result    = $validator->check($this->params);
    if (false === $result)  {
        $this->result['code'] = $validator->code ? : $this->result['code'];
        $this->result['msg']  = $validator->msg  ? : $this->result['msg'];
        throw new \Exception();
    }
} catch(\Exception $e){
    $this->_format();
}

參考:

  1. 《細說PHP 》 兄弟連

  2. PHP手冊

  3. php面向對象(OOP)編程徹底教程

相關文章
相關標籤/搜索