5-php面向?qū)ο?/h2>

什么是面向?qū)ο螅?/h1>

面向?qū)ο笫且环N先進(jìn)的編程模型,相對于面向過程編程,面向?qū)ο蟾哂羞壿嬓?,使程序代碼更加的健壯、易于維護(hù)和好擴(kuò)展。被稱為 OOP編程(Object Oriented Programming)。


面向?qū)ο缶幊?/div>

面向?qū)ο缶哂蟹庋b、繼承、多態(tài)三大特性

1. 封裝:

所有的常量、變量和函數(shù)都要寫在類的內(nèi)部,歸屬于這個類,代碼不能寫在類的外部。
注意:因為PHP是從面向過程發(fā)展過來的,所以PHP里面支持兩種寫法,PHP變量、函數(shù)等等代碼也可以寫在類的外面,但如果是一個門純的OOP的語言,比如Java,所有代碼必須寫在類里面,任何東西不能放在類的外面。

2. 繼承:

一個類A可以繼承自另一個類B,繼承之后,這個類A【一般被稱為子類】中就擁有了那個B類【一般被稱為父類】中的屬性和方法。
注意:比如寫了一個類實現(xiàn)一個功能,然后想添加更多新功能,那么可以直接再定義一個子類繼承自這個類,然后在子類中添加新功能,這樣在不修改原代碼的基礎(chǔ)上添加新功能。

3. 多態(tài):

同一個類的子類中的同一個方法會表現(xiàn)出不同的行為,比如:人都會走路,但不同的人走路的姿勢是不一樣的,這里的人就是父類,子類是不同的人,雖然都有同一個“走路”的方法,但不同的人走路的方式是不一樣。

語法定義

在面向?qū)ο笾兴械拇a都要封裝在一個類中。
定義類的語法:

<?php 

class 類名
{
    代碼;
}

?>

類名由數(shù)字、字母和下劃線組成,不能使用數(shù)字開頭。
業(yè)內(nèi)慣例:類名首字母大寫。后面的單詞首字母大寫。

<?php 

/**
 * UserInfo類
 */
class UserInfo
{

    //.... 這里書寫代碼

}

?>

類的常量、屬性和方法

常量

在類中值不會改變的量,可以定義成類常量,類常量不需要使用 $ 符。


<?php 

/**
 * Math數(shù)學(xué)類
 */
class Math
{
    // 定義常量 不需要使用$,并且以后值不能改變
    const PI = 3.1415926;
}

// 調(diào)用語法
echo Math::PI;
 ?>

屬性

在類中可以定義變量,習(xí)慣叫它為類的屬性。
定義屬性時前面要加上public、protected或者private。如果沒有加PHP認(rèn)為是public的。

<?php 
/**
 * People類
 */
class People
{
    public $username;
    protected $age;
    private $salary;

}

 ?>

注意:也可以使用var,這個是PHP4時候的寫法,相當(dāng)于 public。

<?php 
/**
 * People類
 */
class People
{
    var $username;
    var $age;
    private $salary;

}

 ?>

注意:定義屬性的時候可以進(jìn)行初始化賦值操作。


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

}

 ?>

方法

類中也可以定義函數(shù),稱為類的方法。
定義函數(shù)前面也要加上public、protected或者private。如果不加認(rèn)為是public的。


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        
    }


}

 ?>

對象

一個類是不能使用的,如果要使用類里面的代碼,必須要先new一個對象出來,然后使用這個對象來調(diào)用里面的代碼。

<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        
    }


}

$p1 = new People();
var_dump($p1->username);

 ?>

類和對象的關(guān)系

類相當(dāng)于圖紙,用來描述都有哪些功能和特征,對象就是有真正有這些功能和特征的物品。
一個類可以生成多個對象,每個對象是彼此獨(dú)立的個體,互不影響。

類和對象

$this

在類中可以使用一個特殊變量$this,代表調(diào)用這個方法的那個對象。
簡單點(diǎn)說:類里面要使用類中的屬性必須使用$this就這樣。

<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();
var_dump( $p1->getName() );
 ?>

對象默認(rèn)都是按引入傳遞的【不需要加&】


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();

$p2 = $p1; // 指向的是同一個地址空間
$p2->username = 'p2Username';

var_dump($p1->username);
 ?>

注意:
如果就想要拷貝一個新的出來而不是引入同一個:可以使用clone來克一個新對象


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();

$p2 = clone $p1; // 復(fù)制一個對象,指向的不是同一個地址空間
$p2->username = 'p2Username';

var_dump($p1->username);
 ?>

構(gòu)造函數(shù)和析構(gòu)函數(shù)

每一個類都有兩個特殊的函數(shù),這兩個函數(shù)會自動在兩個時刻調(diào)用。

構(gòu)造函數(shù)

每次new一個新對象時,類中的構(gòu)造函數(shù)就自動被調(diào)用了。

<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct()
    {
        echo 'i am coming....';
    }

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();
var_dump($p1->username);
 ?>

注意:
構(gòu)造函數(shù)的參數(shù):在構(gòu)造函數(shù)中可以設(shè)置參數(shù),如果設(shè)置了參數(shù),那么在new時必須要把參數(shù)加上,如果不傳會報錯。


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username)
    {
        echo 'i am coming....';
    }

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();
var_dump($p1->username);
 ?>

構(gòu)造函數(shù)可以設(shè)置默認(rèn)值。

<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username = 'default')
    {
        echo 'i am coming....';
    }

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }


}

$p1 = new People();
var_dump($p1->username);
 ?>

析構(gòu)函數(shù)

當(dāng)一個對象被刪除時,被自動調(diào)用的函數(shù)。


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username = '')
    {
        echo 'i am coming....';
    }

    // 注意:這里沒有加上 public 相當(dāng)于 public function getAge
    function getAge(){

    }

    public function getName()
    {
        return $this->username; // $this代表當(dāng)前對象
    }

    public function __destruct()
    {
        echo 'i am destory';
    }


}

$p1 = new People();

unset($p1);// 消耗對象

echo 'last';
 ?>

繼承-extends

一個類可以使用extends繼承自另一個類,繼承之后就擁有了父類中的非私有的常量、屬性和方法,一個類只能有一個父類。

<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username = '')
    {
        echo 'i am coming....';
    }

}

/**
 * Male類繼承People類
 */
class Male extends People
{

    public function getInfo()
    {
        echo 'i am male';
    }

}

 ?>

重寫

子類中可以定義一個一樣的東西就覆蓋了父類。


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username = '')
    {
        echo 'i am coming....';
    }

    public function getUserName()
    {
        return $this->username;
    }
}

/**
 * Male類繼承People類
 */
class Male extends People
{
    // 重寫
    public function getUserName()
    {
        echo 'i am getUserName';
    }


    public function getInfo()
    {
        echo 'i am male';
    }

}

 ?>

重載

PHP所提供的"重載"(overloading)是指動態(tài)地"創(chuàng)建"類屬性和方法。是通過魔術(shù)方法(magic methods)來實現(xiàn)的。

當(dāng)調(diào)用當(dāng)前環(huán)境下未定義或不可見的類屬性或方法時,重載方法會被調(diào)用。

父類方法調(diào)用

子類中可以明確指定調(diào)用父類的方法:使用parent關(guān)鍵字


<?php 
/**
 * People類
 */
class People
{
    var $username = 'andy';
    var $age = 12;
    private $salary = 10000;

    public function __construct($username = '')
    {
        echo 'i am coming....';
    }

    public function getUserName()
    {
        return $this->username;
    }
}

/**
 * Male類繼承People類
 */
class Male extends People
{

    public function getInfo()
    {
        parent::getUserName();
        echo 'i am male';
    }

}

 ?>

繼承中的構(gòu)造函數(shù)

如果父類中有構(gòu)造函數(shù),然后子類又有一個構(gòu)造函數(shù),就會導(dǎo)致子類的覆蓋父類的,導(dǎo)致父類的構(gòu)造函數(shù)無法執(zhí)行。

解決辦法:一般子類中如果寫了構(gòu)造函數(shù)那么必須先調(diào)用父類的構(gòu)造函數(shù)。


<?php 
/**
 * People類
 */
class People
{
    public $username = 'andy';
    private $salary = 10000;

    public function __construct($username)
    {
        $this->username = $username;
    }

    public function getUserName()
    {
        return $this->username;
    }
}

/**
 * Male類繼承People類
 */
class Male extends People
{

    public function __construct($username){
        parent::__construct($username);
    }

    public function getInfo()
    {
        return $this->username;
    }

}

$m = new Male('li xiaoming');
var_dump( $m->getInfo() );

 ?>

final關(guān)鍵字

可以把final放到類和方法的前面:代表這個類或者方法不能被繼承。加在類前面:這個類不能被繼承。

<?php 
final Class A{

}

// 出錯
Class B extends A{
    
}

 ?>

訪問控制

在類中可以使用public、protected和private來控制屬性和方法的訪問權(quán)限:

public

公開的:所有位置都可以直接訪問。

protected

受保護(hù)的:只有當(dāng)前類和子類中可以訪問。

private

私有的:只有當(dāng)前類中可以訪問。

static 靜態(tài)

在類中可以使用static定義一個靜態(tài)屬性和靜態(tài)方法。
普通屬性和靜態(tài)屬性的區(qū)別

  1. 語法區(qū)別
  2. 靜態(tài)變量屬于這個類,所以不需要new對象可以直接使用類名訪問
  3. 普通變量屬于一個具體對象,每new出一個對象,里面都有一個這個屬性,必須new出來的對象,所以需要先new一個對象才能使用

<?php 

/**
 * Static學(xué)習(xí)
 */
class Test
{
   public static $count = 0;
}

echo Test::$count;

?>

靜態(tài)屬性

靜態(tài)屬性可以被繼承,只屬于這個類,跟具體new出來的對象沒關(guān)系,可以直接使用類名來操作。


<?php 

/**
 * Static學(xué)習(xí)
 */
class Test
{
   public static $count = 0;
}

/**
 * B
 */
class B extends Test
{
    
}
echo B::$count;

?>

靜態(tài)方法

靜態(tài)方法屬于一個類不屬于任何對象, 所以不需要new可以直接調(diào)用。

<?php 

/**
 * Static學(xué)習(xí)
 */
class Test
{
   public static $count = 0;

   public static function getCount()
   {
        return 'count';
   }
}

echo Test::getCount();

?>

注意:
在靜態(tài)方法中不能訪問普通屬性。

<?php 

/**
 * Static學(xué)習(xí)
 */
class Test
{
   public static $count = 0;
   public $number = 12;

   public static function getCount()
   {
        return $this->number;
   }
}

echo Test::getCount();

?>

self

在類內(nèi)部如果要訪問自己的靜態(tài)屬性或者方法時可以使用self。

<?php 

/**
 * Static學(xué)習(xí)
 */
class Test
{
   public static $count = 0;
   public $number = 12;

   public static function getCount()
   {
        return self::$count;
   }
}

echo Test::getCount();

?>

后期綁定,也叫作晚綁定

代碼

<?php 

class A{
    public function abc()
    {
        echo 'abc in A Class';
    }

    public function bcd()
    {
        $this->abc();
    }
}


class B extends A{
    public function abc()
    {
        echo 'abc in B Class';
    }
}
$b = new A();
$b->bcd();

// 1. 先定義一個 A ,定義 abc
// 2. 在定義一個 B,定義 abc
// 3. 讓B繼承A,這個時候 B的 abc會覆蓋 A的abc
// 4. 在A里面在定義 bcd
// 5. 實例化 A類,調(diào)用 bcd,則輸出什么?
// 6. 那么實例化 B類,調(diào)用 bcd,則輸出什么?

?>

總結(jié):$this是取決于誰調(diào)用,是在真正運(yùn)行的時候才知道的。不是事先定義好的(在編譯的時候已經(jīng)固定了),將來看怎么運(yùn)行的,是屬于后面的才知道,稱為綁定。那么什么是早綁定呢?

后期靜態(tài)綁定

self-早綁定

self是早綁定的,self寫到哪個類里就代表哪個類,無論是哪個對象調(diào)用。


<?php 

class A{

    public static function abc()
    {
        echo 'abc in A Class';
    }

    public function bcd()
    {
        self::abc(); // 已經(jīng)固定,在編譯的時候就確定 self 代表A,無論是哪個類的對象調(diào)用,都是A。
    }
}


class B extends A{
    public static function abc()
    {
        echo 'abc in B Class';
    }
}
$b = new B();
$b->bcd();

// 1. 先定義一個 A ,定義 abc
// 2. 在定義一個 B,定義 abc
// 3. 讓B繼承A,這個時候 B的 abc會覆蓋 A的abc
// 4. 在A里面在定義 bcd
// 5. 實例化 A類,調(diào)用 bcd,則輸出什么?
// 5. 那么實例化 B類,調(diào)用 bcd,則輸出什么?

?>


static-晚綁定

為了給靜態(tài)方法也提供一個晚綁定的功能,所以PHP從5.3開始出了一個static關(guān)鍵字可以用來晚綁定來調(diào)用一個靜態(tài)方法


<?php 

class A{

    public static function abc()
    {
        echo 'abc in A Class';
    }

    public function bcd()
    {
        static::abc(); // static 是靜態(tài)方法的晚綁定,有運(yùn)行時候決定
    }
}


class B extends A{
    public static function abc()
    {
        echo 'abc in B Class';
    }
}
$b = new B();
$b->bcd();

// 1. 先定義一個 A ,定義 abc
// 2. 在定義一個 B,定義 abc
// 3. 讓B繼承A,這個時候 B的 abc會覆蓋 A的abc
// 4. 在A里面在定義 bcd
// 5. 實例化 A類,調(diào)用 bcd,則輸出什么?
// 5. 那么實例化 B類,調(diào)用 bcd,則輸出什么?

?>

parent-早綁定

如果要調(diào)用父類中的靜態(tài)方法


<?php 

class A{

    public static function abc()
    {
        echo 'abc in A Class';
    }

}


class B extends A{
    public static function abc()
    {
        echo 'abc in B Class';
    }

    public function bcd(){
        parent::abc(); // 調(diào)用父類的靜態(tài)方法,屬于早綁定
    }
}
$b = new B();
$b->bcd();


?>

總結(jié):

  1. self和parent是靜態(tài)綁定,是早綁定。
  2. $this和static是晚綁定 :主要要看是哪個對象調(diào)用的。

參數(shù)的類型約束

可以規(guī)定一個函數(shù)上的參數(shù)必須是某種類型的,目前只能做這四種的類型約束:類、數(shù)組、接口或者callable。


<?php 

class Test{

    public function init(A $a)
    {
        var_dump($a);
    }
}

class A{

}

$a = new A();
$t1 = new Test();
$t1->init($a);

 ?>

注意:
類約束時可以傳類和這個類子類的對象都可以,比如下面這個例子:要求傳一個Animal類的對象。但傳了一個Dog類的對象也可以,因為Dog是Animal的子類。

魔術(shù)方法

我們在類中定義好這些方法之后,在某一個特定時刻自動被調(diào)用的方法。比如構(gòu)造函數(shù)是在new一個對象時被自動調(diào)用。


常見的模式方法

__get和__set

當(dāng)要讀取和設(shè)置一個對象中不存在的屬性時該方法就會被調(diào)用了。

類的自動加載

PHP中提供了一個函數(shù)__autoload也是一個魔術(shù)方法,當(dāng)使用一個類時,如果這個類找不到那么這個方法就被調(diào)用。

__autoload

<?php 

function __autoload($className)
{
    var_dump($className);
}

$a = new A();

 ?>

現(xiàn)在我們用一個類時必須先把這個類所在的PHP文件引入進(jìn)來這樣比較麻煩,是否可以讓PHP自動加載我們需要使用的類?
可以使用autoload實現(xiàn):

  1. 一個文件中只寫一個類
  2. 文件名和類名相同
  3. 定義一個autoload函數(shù)根據(jù)類名自動加載相應(yīng)的類

<?php 

function __autoload($className)
{
    include $className . '.php'; // 完成類的載入
}

$a = new A();

 ?>

spl_autoload_register和spl_autoload_unregister

前面的__autoload很早以前就有比較舊,后來又提供了兩個函數(shù)可以提供更加載的自動加載功能:
__autoload只能是這一個函數(shù),使用spl_autoload_register注冊多個自動加載函數(shù)。

注意:
加載函數(shù)也可以是一個類中的一個方法。

<?php 

/**
 * Loader加載器
 */
class Loader
{
    /**
     * Loader加載器
     */
    public static function load($className)
    {
        include $className . '.php';
    }
}

spl_autoload_register('Loader::load');

$a = new A();

 ?>

spl_autoload_unregister:刪除一個已經(jīng)注冊的函數(shù)。

抽象方法和抽象類-abstract

抽象類:只要類中有一個抽象類方法那么這個類必須定義成抽象類。
抽象方法:先定義這個方法的名字和參數(shù),但先不寫具體里面的代碼,這種抽象類必須被子類繼承并且重寫所有抽象類中的抽象方法然后才可以使用。


<?php 

/**
 * Db類是抽象類
1. 里面存在一個抽象方法
2. 類的前面必須加上 abstract 
 */
abstract class Db
{
    abstract public function init();

}

/**
 * Mysql
 */
class Mysql extends Db
{
    public function init()
    {
        echo 'mysql init';
    }
}

$mysql = new Mysql();
$mysql->init();

 ?>

抽象語法:
1 . 如果一個方法前面加上abstract代表這是一個抽象的方法,抽象方法不能有方法體,只有方法名。

  1. 如果一個類中有抽象方法,那么這個類就是抽象類(未完成的類),所以類前面要加上abstract。
  2. 抽象類不能直接實例對象,必須被繼承,子類只有重寫了所有父類中的抽象方法之后這個子類才能使用。
  3. 如果子類沒有重寫父類中所有的抽象方法,那么這個子類也是抽象類。

接口

完全抽象的抽象類就是接口,類里全是抽象方法。

<?php 

/**
 * Db類里面的方法全部為抽象方法,則一般定義為接口,同時去除 abstract關(guān)鍵字,該為 interface
 */
<?php 

/**
 * Db接口
 */
interface Db
{
    const PORT = 3306;
    public function init();

    public function open();

    public function read();

    public function write();

}

 ?>

使用interface定義接口,接口里面只有:

  1. 沒有方法體的方法
  2. 常量

接口是不能用的,必須有一個類實現(xiàn)(implement)了這個接口,這個類才能使用。如果一個類要實現(xiàn)一個接口,那么這個類中必須重寫接口中所有的方法。


<?php 

/**
 * Db接口
 */
interface Db
{
    const PORT = 3306;
    public function init();

    public function open();

    public function read();

    public function write();

}

/**
 * Mysql 實現(xiàn)Db接口
 */
class Mysql implements Db
{
    public function init()
    {
        
    }
    public function open()
    {
        
    }
    public function read()
    {
        
    }
    public function write()
    {
        
    }
}
 ?>

接口繼承

一個接口可以繼承另外一個接口,然后在添加抽象方法,等待其他類去實現(xiàn)。


<?php 

/**
 * Db接口
 */
interface Db
{
    const PORT = 3306;
    public function init();

    public function open();

    public function read();

    public function write();

}

/**
 * Mysql 繼承Db接口,增加了一個sql注入處理
 */
interface Mysql extends Db
{
    public function sqlInjectRemove();
}
 ?>

接口實現(xiàn)


<?php 

/**
 * Db接口
 */
interface Db
{
    const PORT = 3306;
    public function init();

    public function open();

    public function read();

    public function write();

}

/**
 * Mysql 實現(xiàn)Db接口
 */
class Mysql implements Db
{
    public function init()
    {
        
    }
    public function open()
    {
        
    }
    public function read()
    {
        
    }
    public function write()
    {
        
    }
}
 ?>

注意:
一個類可以同時實現(xiàn)多個接口。


<?php 

/**
 * Db接口
 */
interface Db
{
    const PORT = 3306;
    public function init();

    public function open();

    public function read();

    public function write();

}

interface SecretDb{
    // 過濾參數(shù)
    public function filterParams();
}

/**
 * Mysql 繼承Db接口,增加了一個sql注入處理
 */
class Mysql implements Db,SecretDb
{   
    // 實現(xiàn) SecretDb 接口
    public function filterParams(){

    }

    // 實現(xiàn) Db即可
     public function init()
    {
        
    }
    public function open()
    {
        
    }
    public function read()
    {
        
    }
    public function write()
    {
        
    }

}
 ?>

總結(jié):
PHP中的類是單繼承、多實現(xiàn)。

trait

trait是什么?

trait 是比較類似的,可以有自己的屬性和方法,但是不能單獨(dú)被使用實例化。主要用來擴(kuò)展另外一個類的功能,在一個類中需要使用use來引入trait里面的功能。

定義

和類的編寫方式一致。只是將 class 關(guān)鍵字換為 trait。

使用trait

在類中使用use來擁有trait里面所有的東西。

注意:
可以同時use多個trait。

trait方法的沖突

如果同時擁有的多個trait有同名的方法那么就沖突會報錯。

trait屬性的沖突

如果trait里面定義了一個屬性那么類里面不能再定義同名屬性,否則會出錯。
使用trait時可以使用as把沖突的名字起個別名。

使用trait組成trait

在一個trait里面,可以使用其他的trait。

對象序列化

當(dāng)要把一個對象持久化,保存到數(shù)據(jù)庫、文件等等時需要先序列化,轉(zhuǎn)化成字符串保存,取出來用時要先反序列化,把字符串轉(zhuǎn)化回對象再使用。

  1. serialize:序列化
  2. unserialize:反序列化

匿名類

沒有名字的類。

匿名類

如果一個類只使用一次,那么可以不用定義這個類直接new一個匿名類即可。


異常處理

什么是異常處理

異常處理是在面向?qū)ο笾行乱氲奶幚礤e誤的一種方式。當(dāng)出錯時程序throw一個Exception類的對象,然后在通過 try{代碼塊}catch(Exception){處理錯誤信息}finally{ }來捕獲并處理錯誤。

在面向過程中我們每做一個操作都要根據(jù)返回值判斷這個操作是否成功了,一般都是如下的編寫處理方式:

<?php 

@$link = mysql_connect('127.0.0.1', 'root', 'admin');

if(!$link){
    exit('can not link mysql');
}else{
    $status = mysql_selectdb('test');
    if(!$status){
        exit('can not open test datatbase');
    }else{
        //....
    }
    
}

 ?>

面向?qū)ο笾刑峁┝艘环N新的報錯(這個錯誤一般被稱為異常)的語法:

<?php 

/**
 * File類,主要用于文件的操作
 */
class File
{
    public $file;

    public function open($fileName)
    {
        throw new Exception('file can not open');
    }

    public function write()
    {
        throw new Exception('file can not write');
    }

    public function close()
    {
        //file close
        var_dump('file close');
    }
}

$file = new File();
try {

    $file->open('a.txt');
    
} catch (Exception $e) {
    var_dump($e->getMessage()); // 獲取錯誤信息
    var_dump($e->getCode()); // 獲取錯誤代碼
    var_dump($e->getFile()); // 獲取出錯文件信息
    var_dump($e->getLine()); // 獲取出錯信息所在的行號
}


注意:
異常處理是新的處理錯誤的語法:只有面向?qū)ο蟮臇|西支持。

PHP中內(nèi)置的Exception異常類

出錯時所有throw的對象都這個類或者這個類的子類。


異常類

我們可以寫自己的異常類擴(kuò)展這個PHP中自帶的Exception異常類。


<?php

/**
 * Connect
 */
class ConnectException extends Exception
{
   protected $messsage = '連接數(shù)據(jù)庫失敗';
}


class QueryException extends Exception
{
   protected $messsage = '執(zhí)行SQL語句失敗';
}


/**
 * Goods模型
 */
class GoodsModel
{
    public function open()
    {
        if(!mysql_connect('127.0.0.1', 'root', 'admin88')){
            throw new ConnectException();
        }

        if(!mysql_query('select * from test2')){
            throw new QueryException();
        }
    }
}


?>

拋出錯誤:throw

當(dāng)失敗時就throw一個Exception類或者子類的對象,throw之后的代碼就不再執(zhí)行了。


<?php 

class GoodsModel
{
    public function open()
    {

        var_dump('first');
        throw new Exception('連接數(shù)據(jù)庫失敗');
        var_dump('second'); // 這里的代碼不在執(zhí)行

    }
}

$goodsModel = new GoodsModel();
try {

    $goodsModel->open();
    
} catch (Exception $e) {
    var_dump($e->getMessage());
}


 ?>

捕獲:try...catch[...catch....]

當(dāng)發(fā)生異常的時候,然后使用catch捕獲異常。


<?php 

class GoodsModel
{
    public function open()
    {

        var_dump('first');
        throw new Exception('連接數(shù)據(jù)庫失敗');
        var_dump('second'); // 這里的代碼不在執(zhí)行

    }
}

$goodsModel = new GoodsModel();
try {

    $goodsModel->open();
    
} catch (Exception $e) {
    var_dump($e->getMessage());
}


 ?>

一定會執(zhí)行:finally

finally代表是最終的意思,最后的代碼一定會執(zhí)行,例如我們打開一個文件后,無論是讀寫是否正常,最后一定都是需要關(guān)閉文件的。


<?php 

/**
 * File類,主要用于文件的操作
 */
class File
{
    public $file;

    public function open($fileName)
    {
        throw new Exception('file can not open');
    }

    public function write()
    {
        throw new Exception('file can not write');
    }

    public function close()
    {
        //file close
        var_dump('file close');
    }
}

$file = new File();
try {

    $file->open('a.txt');
    
} catch (Exception $e) {
    var_dump($e->getMessage());
} finally{
    
    $file->close();
    
}


相關(guān)資料

面向?qū)ο髮n}
菜鳥教程-面向?qū)ο?/a>

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容