PHP面向對象總結

<?php

Header("Content-type:text/html;charset=utf-8");

/*********************************

《關於PHP面向對象的總結》

**********************************

前言:

1.其實魔術方法也是方法是函數,跟前面講的函數一樣,只不過在類裏面有

$this->name這樣的東西,他就是類的成員屬性,他可以在這個類的任意位置出現。

有可能這個會擾亂你的思路,你只需分分辨清楚就行了,既然都是

函數都道理都是一樣的,有的是有計算功能的,有的有返回值的你用完函數後打印出來,

或者你不打印,在函數裏面不用return 用輸出都行。

2.$this可以理解爲好比是對象的“引用”,我們知道對象訪問他的成員屬性和成員方法時只能用引用來訪問

$this->name;

$this->say();

3.在類中某個成員屬性如果在構造函數中不傳入的話,在外部檢測不到這個成員屬性。

4.$class->nage 這個東西如果單獨寫,除了$this,他就是一個變量,你可以先賦值在輸出試試,

5.魔術方法是在我們操作對象的時候自動運行,我們不確定他什麼時候運行,但是他會自動運行。

6.類直接訪問(不用創建對象)方法Person::tell();如果單純的輸入有值,如果裏面有$this->什麼的,就會報錯了。


一.魔術方法

__construct()

__destruct()

__set()

__get()

__isset()

__unset()

__call()

__toString()

__autoload()

__sleep()

__wakeup()

__clone()

自動加載類方法

__autoload()


對象串行化方法

serialize()

unserialize()


二.常用的關鍵字和修飾字

var

public

protected

private

new

extends

final

static

const

instanceof

clone

abstract

interface

implements


三.單例模式

四.關於多態性

/




1.構造函數__construct()

構造函數可以接受參數,能夠在創建對象時賦值給對象屬性

構造函數可以調用類方法或其他函數

構造函數可以調用其他類的構造函數

<?php
class Person{
    private $name;
    private $age;
    private $sex;

    public function __construct($name,$age,$sex){
        $this->name=$name;
        $this->age=$age;
        $this->sex=$sex;
        $this->run($name);
    }
    private function run(){
        echo $this->name."在跑步";
    }
    public function say(){
        echo $this->name."在說話";
    }
    //下面這個是一個帶參數
    public function say1($name){
        echo $name."在說話";
    }

}
$person = new Person("東方不敗",18,'不詳');
$person->say();
$person->say1("nihao");
?>

調用父類構造函數,調用其他類的構造函數:

public function __constuct(){
parent::__constuct();
classname::__construct();
}

如果想要依次調用幾個父類的構造函數,可以使用類名直接調用構造函數


2.析構函數__destuct()

這個主要是對象在銷燬時自動調用的函數,一個對象在數去引用時,會自動銷燬。

$a=$b=$c=new Person();

$a = null;

unset($b);

一個對象三個引用,失去了兩個還有一個,程序加載完成後會自動銷燬最後一個。


3.賦值函數__set()

__set( $property, $value ) 給一個未定義的成員屬性賦值時調用,(私有成員)


4.取值函數__get()

__get( $property ) 獲取成員屬性的值(私有成員)

先可以判定下是否有這個成員

return isset($this->$property) ? $this->$property : null;

class Person{
    private $name;
    private $age;
    private $sex;
    public function __construct($name,$age,$sex){
        $this->name=$name;
        $this->age=$age;
        $this->sex=$sex;
        $this->run();
    }
    private function run(){
        echo $this->name."在跑步".$this->age;
    }
    public function say(){
        echo $this->name."在說話";
    }
    public function say1($name){
        echo $name."在說話";
    }
    public function __set($field,$value){
        if($field=="age"){
            if($value>200){
                // return "非法數據";
                $value="非法數據";
            }
        }
        $this->$field=$value;
    }
    public function __get($field){
        return $this->$field;
    }
}
$person = new Person("東方不敗",210,'不詳');
$person->say();
// $person->run();
$person->say1("nihao");
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person->age=220;
echo $person->age;





5.__isset()方法用於檢測私有屬性值是否被設定。


如果對象裏面成員是公有的,可以直接使用 isset() 函數。如果是私有的成員屬性,

那就需要在類裏面加上一個 __isset() 方法,然後再使用isset()函數如下

public function __isset($property_name)

{

    return isset($this->$property_name);

}

這樣當在類外部使用 isset() 函數來測定對象裏面的私有成員是否被設定時,就會自動調用 __isset() 方法來檢測。



6.__unset()方法用於刪除私有屬性。

同 isset() 函數一樣,unset() 函數只能刪除對象的公有成員屬性,當要刪除對象內部的私有成員屬性時,

需要使用__unset() 方法:

public function __unset($property_name)

{

    unset($this->$property_name);

}


7.__call() 方法用於監視錯誤的方法調用。

爲了避免當調用的方法不存在時產生錯誤,可以使用 __call() 方法來避免。該方法在調用的方法

不存在時會自動調用,程序仍會繼續執行下去。語法:

public function __call($function_name, $arguments)

{

    ......

}

該方法有兩個參數,

第一個參數 $function_name 會自動接收不存在的方法名。

第二個 $args 則以數組的方式接收不存在的方法的多個參數。


8.__toString()方法用來輸出對象的引用

這個方法也是一樣自動被調用的,是在 直接輸出對象引用時自動調用的, 前面我們講過對象引用是一個指針,

比如說:“$p=new Person()”中,$p 就是一個引用,我們不能使用echo 直接輸出$p,這樣會輸出"Catchable fatal 

error: Object of class Person could not be converted to string"這樣的錯誤,如果你在類裏面定義 

了"__toString()"方法,在直接輸出對象引用的時候,就不會產生錯誤,而是自動調用了 "__toString()"方法,

輸出"__toString()"方法中返回的字符,所以"__toString()"方法一定 要有個返回值(return 語句)。


9.__autoload()方法用於自動加載其他文件中的類。

這個方法是唯一一個不在類中寫的方法。

function __autoload($classname){

    include_once ucfirst($classname)."Controller.php";

}


10.__sleep()方法是對象在序列化時執行的方法

注意了,對象在序列化后里面保存的只是他的屬性(初始化的時候賦值了),函數和方法都是類的,不是對象的。這點要明確

11.__wakeup()方法是對象在反序列化時執行的方法.

在wake.php中

class db {
    private $host;
    private $user;
    private $pwd;
    private $dbname;
    private $mysqli;
    function __construct($host, $user, $pwd, $dbname) {
        $this->host = $host;
        $this->user = $user;
        $this->pwd = $pwd;
        $this->dbname = $dbname;
        $this->db();
    }
    function db() {
        $this->mysqli = new mysqli ( $this->host, $this->user, $this->pwd, $this->dbname );
    }
    function select() {
        $this->mysqli->query("SET CHARSET GBK");
        $sql = "SELECT * FROM ams_archives_rs LIMIT 0,4";
        $result = $this->mysqli
            ->query ( $sql );
        $rows = array ();
        while ( $row = $result->fetch_assoc () ) {
            $rows [] = $row;
        }
        ECHO "<PRE>";
        print_r ( $rows );
    }
    function __sleep(){
        return array_keys(get_object_vars($this));
    }
    function __wakeup(){
        $this->db();
    }
}
session_start();
$chanel = new db("localhost",'root','admin888','ams');
//$chanel->select();
$_SESSION['channel_obj'] = serialize($chanel);


在wakeupa.php中

session_start();
include 'wakeup.php';
$channel_obj=unserialize($_SESSION['channel_obj']);
$channel_obj->select();
//如果在59.php中不寫上__wakeup()方法會連接不上
11.__clone()這個使用關鍵字clone時自動運行的方法
public function __clone(){
    $this->class=2;
}
$person1=clone $person;
echo $person1->class;


二、這幾個關鍵字我們挑選幾個不常用的看看


1.const

他在類的內部使用的方法如下

self::常量名大寫;

他在類的外部使用方法

類名::常量名大寫;


2.extends 英文extend的第三人稱單數是擴展繼承的意思


3.final

可以修飾類和方法

修飾類,這個類不能被繼承

修飾方法,這個方法不能被重寫




4.static

翻譯中文是靜態的意思

用來修飾成員屬性和方法


如果用來修飾成員屬性,初始化後的所有對象都是共用這個成員屬性。

他在類的內部使用方法如下

public function getName(){
    //return 類名::靜態變量;
    //return self::靜態變量;
    //return Person::$name;
    return self::$name;
}
public function setName($val){
    Person::$name=$val;
    //self::$name=$val;
}

$p->setName('東方不敗');

//這裏設置後所有的對象name都是東方不敗了


他在類的外部使用的方法如下

Person::$name;//只能用類名::方法名


如果是用來修飾成員方法,他就不能訪問非靜態成員,因爲非靜態的成員必須用對象的引用來訪問。

因此,用static修飾的方法裏面就一定不使用非靜態成員


5.instanceof

這個是用來判斷一個對象是不是某個類實例化出來的

$p=new Person();

echo intval($p instanceof Person);

//還有一個函數也可以

echo intval(is_a($p,'Person');//PHP官方不建議使用

還有一個函數是用來判斷一個對象是不是某個類的子類實例化出來的(父親級別)

is_subclass_of($p,'Pseson');


6.abstract

中文意思是抽象的意思

這個關鍵字既可以修飾類也可以修飾方法


關於抽象方法:沒有方法體的方法稱作抽象方法,注意在類中聲明抽象方法必須有abstract修飾

function fun();


關於抽象類:如果一個類中有abstract修飾的方法那麼這個類就是抽象類

abstract class Person{

    abstract function fun();

}

抽象類是爲了規定一些共性的成員,一般是給了N個抽象類,抽象類自己不

被實例化,必須由子類繼承過來(所以子類就不能再是抽象類了,而且非抽象方法和成員屬性的訪問

權限也就必須得protected和public),而且子類必須逐一實現這N個抽象方法;而且實現的方法必須

是public 或者不寫;


7.interface

中文意思爲接口

PHP是單繼承,每個類只能繼承一個父類


他是一種特殊的類,

接口裏面的成員必須全是public權限,

接口裏面的方法全都是抽象方法,並且不能用abstract修飾,

接口裏的成員屬性只能是常量(const NAME='hby');


可以寫另外一個接口來繼承(extends)一個接口,用來擴展裏面的方法。

可以寫一個抽象類來實現(implements)一個接口,用來實現裏面的部分方法

可以寫一個普通類來實現(implements)一個接口,用來實現裏面的全部方法

一個類可以同時繼承父類還實現N個接口.

class 類名 extends 父類名 implements 接口1,接口2,...接口n{

    //實現所有接口中的抽象方法;

}


三、單例模式

網上說的意思歸結到一點就是:讓一個類只有一個實例.

如何做到呢?

1.前面學過,每次用 new 類名 的方式,就可以創建一個對象。我們必須禁止

外部程序用 new 類名的方式來創建多個實例。

解決辦法是:我們將構造函數設置成 private ,讓構造函數只能在內部被調用,

而外部不能調用。這樣,這個類就不能被外部用 new 的方式建立多個實例了。

class A{

    private function __construct(){}    

}

$a = new A();


2.我們已經禁止外部用new實例化這個類,我們改如何讓用戶訪問這個類呢?前門堵了,

我們需要給用戶留個後門。

解決辦法是:static 修飾的方法,可以不經實例化一個類就可以直接訪問這個方法。

class A{
    private function __construct(){}
    static function getClassA(){
        return "這裏是後門,可以通過這裏進入類內部..";
    }
}
echo A::getClassA();


3.雖然我們已經進入類內部,但我們要的是這個類的唯一實例?先不管別的,

我們先需要一個實例。通過這個static的方法返回這個實例,如何做呢?

下面的例子我們確實返回了A類的實例,但注意兩次執行返回的不是同一個實例。

class A{
    private function __construct(){}
    static function getClassA(){
        $a = new A();
        return $a;
    }        
}

// 看到這裏確實返回的是 A 的實例.但不是同一個對象.

$a1 = A::getClassA();
$a2 = A::getClassA();
echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);
if($a1 === $a2){ 
   echo "<br> \$a1 \$a2 指向同一對象.";
}else{ 
   echo "<br> \$a1 \$a2 不是一個對象.";
}


4.我們已經通過static方法返回了A的實例。但還有問題。我們如何保證我們

多次操作獲得的是同一個實例的呢?解決辦法:static的屬性在內部也只有一個。

static 屬性能有效的被靜態方法調用。將這個屬性也設置成private,以防止外部調用。

先將這個屬性設置成 null。每次返回對象前,先判斷這個屬性是否爲 null 。

如果爲 null 就創建這個類的新實例,並賦值給這個 static 屬性。如果不爲空,

就返回這個指向實例的 static 屬性。

class A{
    private static $a = null;
    private function __construct(){}
    static function getClassA(){
        if( null == self::$a){
            self::$a = new A();
        }       
        return self::$a;
    }        
}
// 看到這裏確實返回的是 A 的實例.但不是同一個對象.
$a1 = A::getClassA();
$a2 = A::getClassA();
echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);
if($a1 === $a2){ 
   echo "<br> \$a1 \$a2 指向同一對象.";
}else{ 
   echo "<br> \$a1 \$a2 不是一個對象.";
}

最終這裏無論是多少次都是同一個對象。


下面給一個例子

<?php
class Database {
    private $_db;
    static $_instance;
    final private function __construct($dbname,$user='root',$password='',$port='3306') {
        $conStr = "dbname=".$dbname." user=".$user." password=".$password." port=".$port;
        $this->_db = pg_connect($conStr);
    }
    private __clone() {};//不允許被克隆
    public static function getInstance($dbname,$user='root',$password='',$port='3306') {
        if( ! (self::$_instance instanceof self) ) {
            self::$_instance = new self($dbname,$user='root',$password='',$port='3306');
        }
        return self::$_instance;
    }
    public function query($sql) {
        return pg_query($this->_db, $sql);
    }
}
?>



代碼從這開始

**/

class Person{
    const HIGH='170';
    private $name;
    private $age;
    private $sex;
    public $class;
    public function __construct($name,$age,$sex,$class){
        $this->name=$name;
        $this->age=$age;
        $this->sex=$sex;
        $this->class=$class;
        $this->run();
    }
    private function run(){
        echo $this->name."在跑步".$this->age;
    }
    public function say(){
        echo $this->name."在說話";
    }
    public function say1($name){
        echo $name."在說話";
    }
public function __set($field,$value){
if($field=="age"){
if($value>200){
// return "非法數據";
                $value="非法數據"; 
}
}
$this->$field=$value;
}
    public function __get($field){
        return $this->$field;
    }
    public function __isset($property_name){
        return isset($this->$property_name);
    }
    public function __unset($property_name){
        unset($this->$property_name);
    }
    public function __call($function_name,$arguments){
        echo "您所調用的方法".$function_name."參數<br/>";
        echo var_dump($arguments)."不存在";
    }
    public function __toString(){
        return $this->name."qwertyuiop";
    }
    public function __clone(){
        $this->class='2';
    }
    public function tellhigh(){
        echo "身高是".self::HIGH;
    }
}
$person = new Person("東方不敗",210,'不詳','大學');
$person->say();
// $person->run();
$person->say1("nihao");
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person->age=220;
echo $person->age;
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
echo isset($person->class) ? "存在":"不存在";
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
unset($person->age);
echo isset($person->class) ? "存在":"不存在";
echo isset($person->age) ? "存在":"不存在";
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person->age=80;
echo isset($person->age) ? "存在":"不存在";
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person->drink(123,"we");
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
echo $person;//輸出對象的引用
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
//下面寫一個自動加載函數
function __autoload($classname){
    include_once ucfirst($classname)."Controller.php";
}
$mx=new Phone(1999,'4.5英寸','2200mah','魅族MX2','MX2');
$mx->tell();
echo Phone::FUNC;
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person1=clone $person;
echo intval($person1===$person);
echo $person1->class;
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$person->tellhigh();
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
echo Person::HIGH;
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
abstract class Student{
    abstract function say();
    abstract function study();
    public function tell(){
        echo "這是個抽象類裏面的普通方法";
    }
}
class LStudent extends Student{
    public function a(){
        echo "我是LStudent類中的a方法";
    }
    public function say(){
        echo "重寫抽象類中的say方法";
    }
    function study(){
        echo "重寫抽象類中的study方法";
    }
}
$LS=new LStudent();
$LS->a();
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
$LS->say();
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
interface PS{
    const NAME='串口';
    function start();
    function work();
}
interface PS1 extends PS{
    function stop();
}
abstract class PS2 implements PS{
    function start(){
        echo "抽象類實現部分方法這裏是start方法";
    }
}
class PS3 implements PS1{
    function start(){
        echo "抽象類實現全部方法這裏是start方法";
    }
    function work(){
        echo "抽象類實現全部方法這裏是work方法";
    }
    function stop(){
        echo "抽象類實現全部方法這裏是stop方法";
    }
}
$ps=new PS3();
$ps->start();
echo "<br/>---------------------我是華麗麗的分界線---------------------<br/>";
echo PS::NAME;
?>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章