[PHP從小白到大牛]-034 PHP-面向對象(二)

多態

  • 多態(Polymorphism)按字面的意思就是「多種狀態」
  • 接口的多種不一樣的實現方式即爲多態
  • 同一操做做用於不一樣的對象,能夠有不一樣的解釋,產生不一樣的執行結果。

抽象類

  • 聲明一個抽象類, 聲明關鍵字abstract
  • 抽象的方法只是聲明瞭其調用方式(參數),不能定義其具體的功能實現。方法只寫名字, 不寫具體內容
  • 抽象類不能被實例化
  • 抽象方法, 必須定義在抽象類裏面
  • 抽象類能夠爲空, 能夠不包含抽象方法

聲明一個抽象類

abstract class MyAbsClass {
    abstract public function func();
}
複製代碼

具體類繼承而且實現

<?php

abstract class MyAbsClass {
    abstract public function func();
}

class ChildClass extends MyAbsClass {
	// 這樣寫會報錯, 由於沒有實現抽象類中定義的方法
}
複製代碼
<?php

abstract class MyAbsClass {
    abstract public function func();
}

class ChildClass extends MyAbsClass {
    public function func() {
        // 即使什麼都沒有寫, 也沒有關係...
    }
}
複製代碼

若是是抽象類繼承, 則不用實現抽象方法

<?php

abstract class MyAbsClass {
    abstract public function func();
}

abstract class ChildClass extends MyAbsClass {
	// 什麼都沒寫, 也不會報錯...
}
複製代碼

抽象類, 必須有抽象方法

abstract class MyAbsClass {
    public function func(); // 會報錯, 由於沒有abstract關鍵字
}
複製代碼

同理, 含有抽象方法的類, 必須是抽象類

class MyAbsClass // 會報錯, 由於沒有abstract關鍵字 {
    abstract public function func(); 
}
複製代碼

抽象類, 必須有抽象方法, 至少有一個便可

<?php

abstract class MyAbsClass {
    public $name = '張三';
    public $age;

    public function test() {
        echo 'hello';
    }

    abstract public function func();
}
複製代碼

修飾關鍵字順序

  • 類的屬性和方法必須添加訪問修飾符(private、protected以及public)
  • abstract以及final必須聲明在訪問修飾符以前
  • abstract和final不能共存
  • static必須聲明在訪問修飾符以後

final public static functionphp

接口

  • 使用接口(interface),能夠指定某個類必須實現哪些方法,但不須要定義這些方法的具體內容。編程

  • 接口中也能夠定義常量。函數

  • 接口實現關鍵字implementsthis

<?php

interface MyInterface {
    const NUM = 123;

    public function func();

    public function test();
}

class MyClass implements MyInterface {
    public function func() {

    }

    public function test() {
        echo 'hello';
    }
}
複製代碼
<?php

interface MyInterface {
    const NUM = 123;

    public function func();

    public function test() {
        echo "test"; // 會報錯, 不能有具體方法
    };
}


複製代碼
<?php

interface MyInterface {
    const NUM = 123;

    public function func();

    public function test();
}

class MyClass implements MyInterface {
    public function func() {

    }

	// 報錯, 由於沒有實現test()
}
複製代碼
  • 抽象類實現接口, 能夠不用實現其中的方法, 可是抽象類的子類必須實現
<?php

interface MyInterface {
    const NUM = 123;

    public function func();

    public function test();
}

abstract class MyClass implements MyInterface {
	// 沒有實現接口的方法, 也不會報錯
}

class Demo extends MyClass {
    public function func() {
        // 必須實現, 不然報錯
    }

    public function test() {
        // 必須實現, 不然報錯
    }
}
複製代碼
  • 接口也能夠繼承關鍵字extends, 若是接口B繼承了接口A, 而普通類 C實現了接口B, 則A和B全部的方法, C都要實現
<?php

interface A {
    public function aaa();

}

interface B extends A {
    public function bbb();
}

class C implements A {
    public function bbb() {
		// 
    }

    public function aaa() {

    }
}
複製代碼
  • 一個類能夠實現多個接口, 兩個接口中的方法都須要實現
<?php

interface A {
    public function aaa();

}

interface B {
    public function bbb();
}

class C implements A, B {
    public function bbb() {
		// 都得實現, 否則報錯
    }

    public function aaa() {
		// 都得實現, 否則報錯
    }
}
複製代碼
  • 繼承和實現能夠同時使用
<?php

interface A {
    public function aaa();

}

interface B {
    public function bbb();
}

class C {
    public function bbb() {

    }

    public function aaa() {

    }
}

class D extends C implements A, B {
	// 類D繼承C, C實現了A和B
}
複製代碼

抽象類和接口的區別

  1. 抽象類有普通的方法,接口沒有spa

  2. 抽象類能夠有本身的成員屬性和方法,接口只能有public 常量。操作系統

  3. 抽象類無關緊要構造方法,接口沒有構造方法code

  4. 抽象類單繼承,接口多重繼承cdn

類型運算符

  • instanceof用於肯定一個PHP變量是否屬於某一類class的實例
<?php


class A {

}

class B {

}

$a = new A();

var_dump($a instanceof A); // true
var_dump($a instanceof B); // false
複製代碼
  • instanceof也可用來肯定一個變量是否是繼承自某一父類的子類的實例
<?php


class A extends B {

}

class B {

}

$a = new A();

var_dump($a instanceof A); // true
var_dump($a instanceof B); // true
複製代碼
  • instanceof也可用於肯定一個變量是否是實現了某個接口的對象的實例
<?php


class A implements B {

}

interface B {

}

$a = new A();

var_dump($a instanceof A); // true
var_dump($a instanceof B); // true
複製代碼

類型約束

  • PHP5可使用類型約束。
  • 函數的參數能夠指定其類型
<?php


class A {

}

class B {
    
}

$a = new A();


$b = new B();


function test(A $n) {
    echo "ok";
}

test($a); // 輸出ok
test($b); // 報錯, 由於$b是B的實例, 不是A的實例
複製代碼
  • 若是一個類或接口指定了類型約束,則其全部的子類或實現也都如此
<?php


class A {
    public function aaa(B $n) {

    }
}

class B {

}

class C extends B {
    public $a = '123';
}

class D extends A {

}

$a = new A();
$c = new C();
$a->aaa($c);
複製代碼

自動加載(須要的類在不一樣文件)

  • __autoload()函數也能自動加載類和接口
  • spl_autoload_register()函數能夠註冊任意數量的自動加載器,
  • 當使用還沒有被定義的類(class)和接口(interface)時自動去加載。
  • 建議使用spl_autoload_register()函數
  • 再也不建議使用__autoload()函數,在之後的版本中它可能被棄用

C:\Users\Administrator\Desktop\imooc\a.class.php對象

<?php

class A extends B {
    // 會報錯, 由於找不到B
}
複製代碼

C:\Users\Administrator\Desktop\imooc\b.class.phpblog

<?php

class B {

}
複製代碼

引入便可

<?php
include 'b.class.php'; // 引入便可
class A extends B {
    // 會報錯, 由於找不到B
}
複製代碼

使用自動加載

<?php

function myloader() {
    echo '被執行了...';
    include 'b.class.php';
}

spl_autoload_register('myloader'); // 執行myloader

class A extends B {
    
}
複製代碼

使用靜態方法

<?php


class Loader {
    public static function myloader() {
        echo '被執行了...';
        include 'b.class.php';
    }
}


spl_autoload_register(['Loader', 'myloader']); // 執行myloader

class A extends B {
    // 不會報錯
}
複製代碼

也能夠作成構造方法

<?php


class Loader {
    public function __construct() {
        spl_autoload_register([$this, 'myloader']);
    }

    public function myloader() {
        echo '被執行了...';
        include 'b.class.php';
    }
}


$obj = new Loader();

class A extends B {
   
}
複製代碼

接口同理...

類, 抽象類, 對象, 接口的關係

命名空間的基本使用

命名空間概述

  • 從廣義上來講,命名空間是一種封裝事物的方法
  • 在不少地方均可以見到這種抽象概念
  • 例如,在操做系統中目錄用來將相關文件分組,對於目錄中的文件夾來講,它就扮演了命名空間的角色

編程中常見的兩類問題

  • 用戶編寫的代碼與PHP內部的類/函數/常量或第三方類/函數/常量之間的名字衝突
    • 好比引入的文件中, 有當前文件已經使用的類/函數/常量名
  • 爲很長的標識符名稱(一般是爲了緩解第一類問題而定義的)建立一個別名(或簡短)的名稱,提升源代碼的可讀性

定義命名空間

  • 命名空間經過關鍵字namespace來聲明。
  • 若是一個文件中包含命名空間,它必須在其它全部代碼以前聲明命名空間
namespace Project1;
// 代碼...

namespace Project2{
    // 代碼...
}
複製代碼
<?php

namespace MySapce {
    function test()
    {
        echo 'test1';
    }

    test(); // 不會報錯
}

namespace MySapce2 {
    function test()
    {
        echo 'test2';
    }

    test(); // 不會報錯
}
複製代碼
<?php

namespace myspace;
function time() {
    echo 'hello';
}

time(); // 不會報錯, 輸出hello
複製代碼
<?php

namespace myspace1;
function time() {
    echo 'hello1';
}

time(); // 不會報錯, 輸出hello1

namespace myspace2;
function time() {
    echo 'hello2';
}

time(); // 不會報錯, 輸出hello2
複製代碼

指定命名空間

<?php

namespace myspace1;
function time() {
    echo 'hello1';
}


namespace myspace2;
function time() {
    echo 'hello2';
}

\myspace1\time(); // hello1
複製代碼

使用系統的time方法, \表示全局

<?php

namespace myspace1;
function time() {
    echo 'hello1';
}


namespace myspace2;
function time() {
    echo 'hello2';
}

echo \time(); // 1567210241 系統函數, 返回時間戳
複製代碼

定義命名空間

  • 聲明單個命名空間namespace MyProject

  • 定義子命名空間namespace MyProject\Sub\Level;

  • 能夠在同一個文件中定義多個命名空間

  • 若是沒有定義任何命名空間,全部的類與函數的定義都是在全局空間,與PHP引入命名空間概念前同樣。

  • 在名稱前加上前綴\表示該名稱是全局空間中的名稱,即便該名稱位於其它的命名空間中時也是如此

__NAMESPACE__常量

常量__NAMESPACE__的值是包含當前命名空間名稱的字符串

在全局的,不包括在任何命名空間中的代碼,它包含一個空的字符串。

<?php

namespace hello\hello1;
var_dump(__NAMESPACE__); // hello\hello1
namespace hello\hello2;
var_dump(__NAMESPACE__); // hello\hello2
複製代碼
<?php

var_dump(__NAMESPACE__); // ""
複製代碼

非限定名稱, 徹底限定名稱, 限定名稱(絕對路徑, 相對路徑)

<?php

namespace A\B;
class MyClass {
    public function __construct() {
        echo '空間A\B 中的類 實例化了' . "\n";
    }
}

namespace A;
class MyClass {
    public function __construct() {
        echo '空間A 中的類 實例化了' . "\n";
    }
}

$obj = new MyClass();// 非限定名稱 就近
$obj = new \A\B\MyClass();// 徹底限定名稱 絕對路徑
$obj = new \A\MyClass();// 徹底限定名稱 絕對路徑
$obj = new B\MyClass();//限定名稱 相對路徑
複製代碼

include不會改變當前命名空間, 可是include以後, 可使用引入文件中的命名空間

C:\Users\Administrator\Desktop\imooc\aaa.php

<?php

namespace aaa;

function demo() {
    echo 'aaa';
}
複製代碼

C:\Users\Administrator\Desktop\imooc\bbb.php

<?php

namespace bbb;

function demo() {
    echo 'bbb';
}

include 'aaa.php';
demo(); // bbb
var_dump(__NAMESPACE__); // bbb
\aaa\demo(); // 可使用aaa.php的命名空間
複製代碼

動態調用命名空間

動態調用函數

<?php


function demo() {
    echo "demo\n";
}

demo(); // 調用demo

$a = 'demo';
$a(); // 一樣能夠調用demo
複製代碼

動態實例化對象

<?php


class A {
    public function demo() {
        echo "demo\n";
    }
}

$a = new A();
$a->demo();

$b = "A";
$c = new $b;
$c->demo();
複製代碼

動態調用命名空間

<?php

namespace A\B;

function demo() {
    echo "demo\n";
}

namespace A;

demo(); // 會報錯, 由於當前命名空間下, 沒有demo()
複製代碼
<?php

namespace A\B;

function demo() {
    echo "demo\n";
}

namespace A;

\A\B\demo(); // 這就會正常了
複製代碼
<?php

namespace A\B;

function demo() {
    echo "demo\n";
}

namespace A;
$a = '\A\B\demo'; // 效果同樣, 由於都是徹底限定名稱
$a = 'A\B\demo';
$a(); 
複製代碼
<?php

namespace A\B;

function demo() {
    echo "demo\n";
}

namespace A;
$a = 'B\demo'; // 報錯, 不支持相對路徑
$a();

複製代碼
相關文章
相關標籤/搜索