[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();

复制代码
相关文章
相关标签/搜索