PHP面向对象

【一】目标

1.类声明语法------试声明student类,有score属性和study方法

2.权限封装---------知道public、protected、private各自的可见范围

3.继承---------------写A类,再写B类继承自A类,且要重写A类中的某个方法

4.静态属性与静态方法-----知道static静态方法需要用类名..方法名0调用

5.魔术方法--------了解常用魔术方法分别在什么时间被调用

6.写一个抽象类,并用2个子类分别继承实现分析这2个子类有什么共同特点?

7.写一个接口,并用2个类分别继承实现分析这2个类有什么共同点?

基本语法:声明,权限,继承,静态属性和方法,魔术方法,抽象类,接口

 

【二】基础

<?php
    //对象的声明,将函数放到对象里
    class oneclass{
//方法
function one(){ echo "666"; } } //实例化对象 $class = new oneclass(); // 函数调用 $class -> one(); ?>

(1)属性和方法

将变量赋值放到类中,便成为了属性;将函数放到类里,便成了方法

属性和方法的调用:

<?php
    //放到对象里
    class oneclass{
        public $name = '我是属性';
        function one(){echo "我是方法";}
    }
    //实例化对象
    $class =  new oneclass();
    // 方法调用
    $class -> one();
    //属性调用
    echo $class->name;//调用属性时可以不加$
?>

注意:方法和属性加到类里时前面要加入权限声明,否则默认public

 

(2)类的声明

语法:class 类名{...}

注意:类名不区分大小写,但是Linux下区分,所以要保持一致。且命名采用驼峰法,一般首字母大写

<?php
    //类的声明
    class person{
        //属性声明
        public $name = 'wang';
        //方法声明
        public function man(){
            echo "1111";
        }
    }
    //调用类的话,要先new一个对象,且实例化时不区分大小写,但在Linux下严格区分大小写,所以要避免不一致的情况。命名时用驼峰法
    $person = new PERSON();
    $person -> man();
    echo $person->name;
?>

 

(3)属性赋值的变化

属性不能赋值表达式?

5.6版本开始支持表达式,例如public $rand = 1+1;

 

(4)类与对象关系

类是同类事物共同特点的抽象描述;而对象是以类作为模板,形成的具体实例

所以当new + 类名时,便成为new一个对象,即实例化对象

<?php
    //类的声明
    class person{
        //属性声明
        public $name = 'tony';
        //方法声明
        public function man(){
            echo "1111";
        }
    }
    //实例化一个对象,赋值给变量
    //new类名时,内存便会产生一个对象,开辟新空间存放属性和方法名
    $person = new PERSON();
    $person1 = new PERSON();
    echo $person->name;
    $person1 ->name = 'tony1';
    echo $person1->name;
?>

注意:

①这里改变的属性值不是类里的属性值,而是开辟出的新空间的值;

②开辟的新空间只存放属性和属性值,至于方法只存放方法名,不存放函数

 

(5)$this本对象、self本类、parent父类

①$this是伪变量,谁实例化对象就是谁。简单理解谁调用就是谁

<?php
    class Person{
        public $name = 'tony';
        public $goods = 'dogs';
        public function buy(){
            echo "拍电影吧".$this->name;
        } 
    }
    $person = new Person();
//调用new出来的对象中的方法,所以this指的是new出来的对象。而不是类本身
$person -> buy(); ?>

 ②self本类,即class类

类名随意改,函数内部用self替换类名,代表调用本类

③parent父类

作用:实现某些情况下子类和父类的兼容,即在继承的子类里做的修改不会影响父类。二者可以同时共存,不会覆盖重写

先举个普通例子:

<?php
    class Single{
        public $value = 1;
    }
    class Test extends Single{
        public $value = 2;//子类继承后对变量进行覆盖重写
    }
    $test = new Test();
    echo($test->value);
?>

parent父类案例:

<?php
    class Single{
        public function __construct(){
            echo rand(0,10);
        }
    }
    class Test extends Single{
        public function __construct(){
            parent::__construct();
            echo 2;
        }
    }
    $test = new Test();
?>

总结:self()调用本类方法\属性;parent()调用父类方法\属性

 

(6)封装MySQL类

注意:原生MySQL的api自5.0版本开始逐渐废弃,在将来预计会完全移除。虽然有向下兼容特效,但开发中还是推荐使用mysqli

用封装MySQL连接数据库

<meta charset="utf-8">
<?php
    class Mysql{
        public $link;
        //连接数据库
        public function coon(){
            $cfg = array(
                'host' => 'localhost',
                'user' => 'root',
                'password' => 'root',
                'db' => 'user',
                'charset' => 'utf8'
            );
            //连接数据库(地址,用户,密码,选库)
            $this ->link = mysqli_connect($cfg['host'],$cfg['user'],$cfg['password'],$cfg['db']);
            if(!$this ->link){
                die("连接失败:".mysqli_error());
            }else{
                echo "连接成功";
            }
        }
        //发送查询
        public function query($sql){
             return    mysqli_query($this->link,$sql);
        }
        //查询获取所有数据,返回数据
        public function getAll($sql){
            $array = array();
            $res = $this ->query($sql);
            // mysqli_fetch_assoc($res);//数组
            while ($row = mysqli_fetch_assoc($res)) {//遍历数组
                $data[] = $row;
            }
            return $data;
        }
    }
    $sql = new Mysql();
    $sql -> coon();    
    var_dump($sql->getAll('select* from user'));
?>

注意:每连接一次(刷新页面),便会增加一次连接数Connection id

 

(7)构造方法和析构方法----------(简单即为构造和销毁construct和destruct)

①构造方法(construct构造)

与面向对象调用方式不同,构造方法的类,一旦被实例化,就会被调用

②析构方法(destruct销毁)

同样也是实例化后便被调用

③构造方法传参:直接在调用时传入即可

注意:析构方法对象销毁时被调用

<?php
    class Human{
        public function __construct(){
            echo "构造方法";
        }
public function __destruct(){
echo"析构方法";
} }
new Human();//调用执行 ?>

构造函数与析构函数调换位置后输出顺序依然不变,因为实例化对象时会先执行构造函数

案例:

<?php
    class Human{
        public function __destruct(){
            echo "调用2<br>";
        }
        public function one(){
            echo "调用One函数<br>";
        }
        public function __construct(){
            echo "调用1<br>";
        }    
    }
    $a = new Human();
    $a -> one();
?>

输出顺序:1,one,2

③析构函数销毁时间:变量赋其他值;被人工销毁unset();页面结束

④构造方法的旧式声明:一个和类名同名的方法,被理解为构造方法。老旧的PHP代码会遇到,遇到时认识即可(可以传参)

<?php
    class Human{
        //方法名和类名一致时会被理解为构造方法
        public function Human($a){
            echo "调用";
        }
    }
    $a = new Human('形参');
?>

 

(8)类的封装性

封装性:类中的某些方法或属性不允许外部调用

可以通过开放部分接口来间接调用,写个简单例子

<?php
    class Human{
        //方法名和类名一致时会被理解为构造方法
        public function aa(){
            echo "调用1";
        }
        public function __construct(){//通过调用构造函数来间接调用方法aa()
            $this -> aa();//我是内部调用
        }
    }
    $a = new Human();//我是外部调用
?>

类似于ATM机,只能输入密码,而不能查询。因为这里只开放了输入对比的接口

不封装的缺点:可以在外部调用获取内部函数或变量,安全性差

<?php
    class Atm{
        //返回数据库存储的密码
        public function getPwd(){
            return '123456';
        }
        //对比密码
        public function checkPwd($pwd){
            return $this -> getPwd() == $pwd;
        }
    }
    $atm = new Atm();
    //不封装时在外部会可以调用到内部函数,获取密码
    echo '存储密码为'.$atm->getPwd()."<br>";
    if($atm -> checkPwd('123456')){
        echo "密码输入正确";
    }else{
        echo "密码输入错误";
    }
?>

为了封装函数,保护重要数据。将返回数据库存储密码的行的权限改为protected(保护),则该函数便被封装了起来

通过调用公共接口即可间接调用方法

              //返回数据库存储的密码
        protected function getPwd(){
            return '123456';
        }

 

(9)类的继承

语法:extends继承、扩展

class ParClass{}
class SubClass extends ParClass{}

接下来,首先看个问题

<?php
    include 'footer.php';//不存在会继续终止
    require 'header.php';//不存在会终止执行
    function check(){...}
?>

引入的文件里可能会有函数名与check相同,导致运行出现问题

详解:结合下面代码进行解析

继承的好处:

       ①子类可以继承父类的方法和属性,例如底下案例里通过实例化调用子类来调用继承自父类的函数method;

       ②允许覆盖和修改父类的方法属性或新增方法,例如check函数的覆盖重新;

案例:

<?php
    class one{
        function check(){
            echo "检查1";
        }
        function method(){
            echo "方法1";
        }
    }
    //two相对于one 来说是子类,此时one类里的方法可用,比如通过子类two调用父类的method方法
    class two extends one{
        function check(){
            echo "检查2";
        }
    }
    $three = new two();
    $three -> check();//这里会输出“检查2”,因为two对one进行了继承修改
    $three -> method();//通过子类two调用父类的method方法
?>

 

(11)final类和final方法

final类不能被继承,且final方法不能被子类重写

①类无法继承

<?php
    final class One{}
    class Two extends One{
        public function a(){
            echo "123";
        }
    }
    $three = new Two();//检验后,会提示无法继承错误
?>

②方法可以通过子类继承调用,但无法覆盖重写

<?php
    class One{
        final public function check(){
            echo('父级');
        }
    }
    class Two extends One{
        public function a(){
            echo "子级1";
        }
        public function check(){
            echo "子级2";
        }
    }
    $three = new Two();
    $three -> check();//输出父级,所以可以继承
?>

 

(12)三种权限的详解

类中的权限一共3中,三种权限包含public(公共的),protected(保护的),private(私有的)

①public

内外部均可调用,子类可以继承和重写

<?php
    class Human{
        public $money = 3000;
        public function one(){
            echo $this->money;
        }
    }
    class Stu extends Human{}
    $Stu = new Stu();
    // 变量调用
    echo $Stu->money;
    //方法调用
    echo $Stu->one();
?>

②protected

不能在外部直接调用,只能通过内部开放接口调用。但是可以被子类覆盖重写

<?php
    class Human{
        public $money = 3000;
        protected $pwd = '123456';
        public function one(){
            echo $this->money;
        }
    }
    class Stu extends Human{
        public function show(){
            return $this->pwd;
        }
    }
    $Stu = new Stu();
    // protected权限的变量,不能在函数外部调用。只能通过子类间接调用
    echo $Stu->show();
?>

③private(私有的)

外部不可以被调用,内部可被调用。不可以被继承

 

(13)静态属性和静态方法

①为什么实例化类?

为了得到类里的属性和方法,通过实例化出来的对象调用

②静态方法

类的方法和属性的调用,可以不通过实例化类来调用方法,这时我们可以通过静态方法来调用

③静态属性

<?php
    class Math{
        //声明静态属性
        static public $name = 'Tony';
        //声明静态方法
        static public function add($a,$b){
            return $a+$b;
        }
    }
    $math = new Math();
    echo Math::add(1,2);
    echo Math::$name;
?>

优势:略过实例化步骤,直接调用属性和方法

 

(14)类常量

先说下常量:常量类似变量,但是常量一旦被定义就无法更改或撤销定义。全局均可被调用

常量语法:define(常量名,常量值,是否对大小写敏感(默认不敏感true))

<meta charset="utf-8">
<?php
    define('name', 'Tony');
    class Math{
        public function test(){
            echo name;
        }
    }
    $math = new Math();
    $math->test();
?>

因为常量是全局性的,可能有命名冲突的情况,造成运行问题。

为了避免这种情况的出现,可以把常量写到类里,用类常量来解决

类常量:

调用时类名::常量即可调用

<?php
    class Math{
        const name = 'Tony';
        public function test(){
            echo Math::name; //类常量的调用为类名::常量名;
        }
    }
    $math = new Math();
    $math->test();
?>

 

(15)单例模式

简单理解:单例就是类只能被实例化一次,只能得到一个对象

购物商场用到单例模式

思路:按步骤分为

     1. 创建普通类;2. 保护构造方法,封装起来(保护后不能调用);3. 所以要在封装后在内部调用,从而实现对外开放一个接口;

     4.设为静态,移除控制权,从而不实例化调用;5.  添加判断;6. final禁止继承

单个实例对象,即只能实例化一个对象

①普通类的实例

<?php
    class Single{
        public $rand;
        public function __construct(){
            $this->rand = mt_rand(10,300);//mt_rand()随机数
        }
    }
    var_dump(new Single());//115
    var_dump(new Single());//148
?>

这里我实例化了类两次,得到两个对象,且两次数值不一样。由此总结出一个类可以实例化出多个对象

②单例模式案例

实例化放到类里,加上条件判断

<?php
    class Single{
        public $rand;
        static public $ob;
        protected  function __construct(){
            $this->rand = mt_rand(10,300);//随机数
        }
        static public function out(){
            if (Single::$ob === null) {//判断是否实例化
                Single::$ob = new Single();
            }
            return Single::$ob;
        }
    }
    var_dump(Single::out());//输出222
    var_dump(Single::out());//输出222
?>

两次输出一样

上例还未完成,因为继承后的子类里再次实例化时,还是会产生多个不同结果

<?php
    class Single{
        public $rand;
        static public $ob;
        //final不允许被子类重写
        protected  function __construct(){
            $this->rand = mt_rand(10,300);//随机数
        }
        static public function out(){
            if (Single::$ob === null) {//判断是否实例化
                Single::$ob = new Single();
            }
            return Single::$ob;
        }
    }
    class Test extends Single{
        public function __construct(){
            echo rand(20,300);//此处被子类重写
        }
    }
    new Test();
    new Test();
?>

对此我们用final来禁止重写,因为final类不能被继承,且final方法不能被子类重写

 

(16)魔术方法

在某些场景下可以自动调用的方法,即为魔术方法

举例:__construct、__destruct、__set、__get、__isset、__unset、__call

详解:

__construct: 构造方法,new 实例时,自动调用

__destruct: 析构方法,对象销毁时自动调用

__get(属性名): 当读取对象的一个不可见属性时,自动调用,并返回值

不可见:未定义或无权访问时

__set(属性名,属性值):当对一个不可见的属性赋值时,自动调用

__isset(属性名):当用isset,或empty判断一个不可见属性时,自动调用

__unset(属性名): 当unset一个不可见属性时,自动调用

不可见属性:未定义,不能访问(受保护或者私有),即外部不能访问,protected和private.

简单理解就是:在外部没有访问权限的都是不可见属性

案例:

__get():

<?php
    class Single{
        public function __get($a){
            echo $a;
        }
    }
    $single = new Single();
    $single->tony;//这里调用了一个未定义的属性(不可见属性),所以自动触发了__get(),并返回值。获取不可见属性时触发,返回属性值
?>

__set():设置不可见属性时自动触发

    <?php
        class Single{
            public function __set($a,$b){
                echo $a.$b;
            }
        }
        $single = new Single();
        $single -> name='Tony';
    ?>

_isset():当用isset,或empty判断一个不可见属性时,自动调用

       <?php
        class Single{
            public function __isset($a){
                echo $a;
            }
        }
        $single = new Single();
        isset($single -> tony);
    ?>

__unset(属性名): 当unset一个不可见属性时,自动调用

       <?php
        class Single{
            public function __unset($a){
                echo $a;
            }
        }
        $single = new Single();
        unset($single -> tony);
    ?>

 

(17)魔术方法的意义

作用:防止对类的随意修改;运用__set()实现数据库数据添加

 先来根据案例介绍

<?php
    class Single{    
    }
     //实例化一个对象,赋值给变量
    //new类名时,内存便会产生一个对象,开辟新空间存放属性和方法名
    $single = new Single();
    $single -> name = 'tony';
    echo $single ->name;
?>

①这里改变的属性值不是类里的属性值,而是开辟出的新空间的值;

②开辟的新空间只存放属性和属性值,至于方法只存放方法名,不存放函数

 代码解析:

上面的代码里,Single类本身失去了对代码的控制权,因为继承的子类可以随意修改覆盖,这里便可以通过魔术方法来限制

<?php
    class Single{    
        public function __set($a,$b){
            echo"禁止随意添加属性";
        }
    }
    $single = new Single();
    $single -> name = 'tony';
?>

总结:通过魔术方法来限制对父类的添加覆盖和获取。

案例:thinkPHP里,可以通过触发魔术方法,直接将数据添加到数据库

//ORM方式,原理:设置了__set()魔术方式
<?php $this->name = 'tony'; $this->age = '23'; $this->add(); ?>

 

(18)自动加载

实例化某个类时,如MySQL,需要先require()。如果类比较多,目录也就比较多,require引入文件时将显得很麻烦。这时需要一个自动化的解决方案----自动加载。

<?php
    function myload($class){//这里$class为实例化的类名
        echo $class."?";
    }
    //注册一个函数为自动触发函数--调用/实例化一个不存在的类时便会自动触发
    spl_autoload_register('myload');
    new mySql();
?>

解析:new mySql()会在本页面查找mysql类,不存在时便会触发sql_autoload_register()里注册的自动触发函数

被注册函数的形参,上例为$class,会接受实例化的类名。

<?php
    function myload($class){
        include './'.$class.'.class.php';//这里便会引入(自动加载)mySql.class.php文件
    }
    //注册一个函数为自动触发函数--调用/实例化一个不存在的类时便会自动触发
    spl_autoload_register('myload');
    new mySql();
?>

mySql.class.php:

<?php
    class mySql{
        public function __construct(){
            echo "789";
        }
    }
?>

总结:简单理解所谓的自动加载并不是真的自动加载,而是利用spl_autoload_register()注册自动触发函数,利用函数里面设定的include内容来加载想要加载的文件。并且new里面的一个类名。thinkPHP里经常遇到类名与文件名一致,这便用到了自动加载功能。

 

(19)抽象类和抽象方法

问题由来:项目组A组负责底层数据库,B组负责调用接口,实现业务逻辑。为了分开两组进度,避免相互影响,从而产生了抽象类和抽象方法模板

抽象类和抽象方法实现模板的功能,实现数据与逻辑分离。其原理类似于螺母和扳手,都采用国标进行生产。而这里的抽象类和抽象方法,功能类似于国标。为数据和逻辑规定了模板。

语法:abstract + 类名,则为抽象类;abstract + 方法名,则为抽象方法。

注意:

抽象方法没有方法体,即代码块

②抽象类里的方法都是抽象方法?

    NO!抽象类里可以有已经实现的方法,是完整的方法,即有代码块。例如下例中的check(),但之前不能加abstract

③抽象类里只要有一个抽象方法,则类仍然是抽象的。抽象类不能被实例化。否则会报错

Fatal error: Cannot instantiate abstract class Test in C:\PHPTutorial\demo1.php on line 30

翻译为抽象类不能被实例化

<?php
    abstract class Test{
        /*
         *参数:sql语句
         *返回值类型:array
        */
        abstract public function getAll($sql);
        /*
         *参数:sql语句
         *返回值类型:array
        */
        abstract public function getRow($sql);
        //已完成方法
        public check(){
            echo "我是已完成方法";
        }
    }
    //逻辑方法方面,只需知道getAll()方法;而数据库方面照着以上模板写sql执行。从而实现逻辑和数据分离

    //接下来数据库方面想写数据,通过继承来实现上面模板的继承。继承时必须对每个方法都进行一一实现,少一个也不行
    class Mysql extends Test{
        public function getAll($sql){

        };
        public function getAll($sql){

        };
    } 
?>

 

(20)接口的概念

 抽象类可以理解为”类的模板”,接口则是”方法模板”。

接口粒度更小,用于描述通用的方法。

<?php
    interface fly1{
        public function fly($oil,$height);
    }
    interface run1{
        public function run($speed,$width);
    }
    interface water1{
        public function water($depth);
    }
    //声明一个类,实现其接口
    class Super implements fly1,run1,water1{
        //与抽象类和抽象方法相同,对于声明类里所带的接口,必须对每个接口都进行一一实现,少一个也不行
        public function fly($oil,$height){
            echo "飞";
        }
        public function run($speed,$width){
            echo "跑";
        }
        public function water($depth){
            echo "游泳";
        }
    }
    $super = new Super();
    $super -> fly(1,2);//这里因为上面接口规定了必须传参,所以不管用不用都得传入,否则会报错
?>

 

(21)接口的语法

①接口本身就是抽象的,方法前不用加abstract;

②接口里的方法,只能是public;

③类可以同时实现多个接口。例如下例的fly1,run1,water1

//声明一个类,实现其接口
    class Super implements fly1,run1,water1{
        //与抽象类和抽象方法相同,对于声明类里所带的接口,必须对每个接口都进行一一实现,少一个也不行
        public function fly($oil,$height){
            echo "飞";
        }
        public function run($speed,$width){
            echo "跑";
        }
        public function water($depth){
            echo "游泳";
        }
    }

总结:抽象类相当于一类事物的规范;接口:组成事物的零件的规范

 

(22)异常处理

 程序运行的每个环节都可能出错,要判断程序的运行逻辑,要靠返回不同的值

主要靠两部分:①抛出异常;②捕获异常

//抛出异常
//
参数(异常信息,异常错误码),两个参数共同定位了错误的位置 throw new Exception("抛出异常,错误码为1", 1);
    //捕获异常,$e为错误码
try
{ var_dump(t1()); }catch(Exception $e){ var_dump($e);//输出验证即可分析出$e为对象类型 }

报错:

object(Exception)#1 (7) {
  ["message":protected]=>
  string(8) "t1返回"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(1)
  ["file":protected]=>
  string(24) "C:\PHPTutorial\demo1.php"
  ["line":protected]=>
  int(7)
  ["trace":"Exception":private]=>
  array(1) {
    [0]=>
    array(4) {
      ["file"]=>
      string(24) "C:\PHPTutorial\demo1.php"
      ["line"]=>
      int(21)
      ["function"]=>
      string(2) "t1"
      ["args"]=>
      array(0) {
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
}

作用:利用报错机制,定位到相关错误行,打印出具体信息

<?php
    function t1(){
        if(rand(1,10)>5){
            //参数(异常信息,异常错误码)
            //两个参数共同定位了错误的位置
            throw new Exception("t1返回", 1);
        }else{
            t2();
        }
    }
    function t2(){
        if(rand(1,10)>5){
            throw new Exception("t2返回", 2);
        }else{
            return true;            
        }
    }
    try{
        var_dump(t1());
    }catch(Exception $e){
        // var_dump($e);//输出验证即可分析出$e为对象类型
        echo '文件位置为:'.$e->getFile()."<br>";
        echo "行号".$e->getLine();
    }
?>

结合PHP手册查阅可以知道:getFile()错误获取文件位置、getLine()获取错误所在行等错误信息。而Expection为所有异常的基类

适用场景?

不该出错的重要地方,却有可能出错,就用异常。比如连接数据库,尤其是连接远程数据库时(断网);查询用户是否存在,可能返回true/false,此时就用return;上传文件时(上传过程断网)。出错时要写到错误日志

 

(23)命名空间

多个人开发项目,函数名很容易重复。用了类之后,类之间的方法名被类分开,重名也没关系。

但是当项目更大时,类名也有可能重复。此时就要用到命名空间,来避免重名。

注意:①命名空间语句必须顶行,且之前不可以有任何输出

案例:

<?php
    namespace name;//命名空间---相当于创建了一个文件夹
    include 'two.php';
    class Test1{
        public function __construct(){
            echo "666";
        }
    }
    new Test1();
?>

two.php:

<?php
    namespace name1;
    class Test1{
        public function __construct(){
                  echo "333";
                }
    }
?>

最终会输出666,也就是调用了one.php里的函数。

如果去掉命名空间语句,再次测试会发现报错提示:Fatal error: Cannot redeclare class Test1。无法重新声明Test1

这里如果想调用two.php里的同名函数怎么办呢?

①原理类似于Linux下的文件查询操作cd\...\...;②之前说过,命名空间相当于创建了一个文件夹,现在我们要通过cd来查看内部文件;③定向调用

//two.php里命名空间为name1,所以相当于在name1文件夹下查看文件
new
\name1\Test();

所以,上例可以改为

<?php
    namespace name;//命名空间---相当于创建了一个文件夹
    include 'mySql.class.php';
    class Test{
        public function __construct(){
            echo "666";
        }
    }
    new \name1\Test();//这时便会输出333
?>

有了命名空间可以明确指出运用的类

上例继续修改

one.php:

use \name1\Test1;
new Test1();

two.php:

<?php
    namespace name1;
    class Test1{//改名为Test1
        public function __construct(){
            echo "333";
        }
    }
?>

但是这种写法需要修改文件,有时没有相应权限。所以这里我们可以用别名as

use \name1\Test as newName;
new newName();//直接new()别名

这样便可以访问

注意:命名空间可以创建多层,调用时按照cd原理逐层读取即可。例如

one.php:

use \name1\one\two\three\Test as newName;
new newName();

two.php:

<?php
    namespace name1\one\two\three;
?>

注意:

①命名空间声明位置必须位于首行;②声明后,其后的函数、类都将被封锁在命名空间里;

③引入其他页面后,自身空间不受干扰;④如果想明确使用某空间下的类,可以从根目录下逐层寻找读取,原理类似Linux的cd;

⑤若频繁使用某个空间下的类,可以先用use声明,然后as别名,避免冲突;⑥自动加载函数的参数,包含“空间路径\类名”

 

(24)延迟绑定

先来看个例子:

<?php
    class One{
        public function demo1(){
            echo "父类";
        }
        public function demo2(){
            $this->demo1();
        }
    }
    class Two extends One{
        public function demo1(){//继承重写
            echo "子类";
        }
    }
    $test = new Two();
    $test->demo2();//输出结果为"子类"
?>

以上输出结果为"子类",虽然demo2是调用demo1实现的,但是这里还是打印出子类改写的结果,为什么呢?

因为这里用$this当前对象调用,而$this伪元素是谁调用就指向谁,所以会输出“子类”

对上面代码进行修改,改为$self本类

<?php
    class One{
        public static function demo1(){
            echo "父类";
        }
        public static function demo2(){
            self::demo1();
        }
    }
    class Two extends One{
        public static function demo1(){//继承重写
            echo "子类";
        }
    }
    Two::demo2();//这里会输出父类“”
?>

上面会输出父类,再做些修改

static::demo1();//输出“子类”

此时输出“子类”,这便是延迟绑定

简单理解:所谓延迟绑定就是在定义时未做出绑定,知道后面调用时才决定出绑定哪个。完整代码

<?php
    class One{
        public static function demo1(){
            echo "父类";
        }
        public static function demo2(){
            static::demo1();
        }
    }
    class Two extends One{
        public static function demo1(){//继承重写
            echo "子类";
        }
    }
    One::demo2();//调用时才决定出绑定哪个类
    Two::demo2();
?>

 

(25)超载的static

静态变量static在函数执行完毕后不会被重写

static用法场景:延迟绑定,静态属性和静态方法

用在变量前构成静态变量,用在类里的属性前则构成静态属性,类里的方法前则构成静态方法,用在静态方法里调用则构成延迟绑定

 

(26)多态

面向对象的3大特征:封装、继承、多态

PHP数据类型:4种标量类型(整型,浮点型,字符串,布尔值),2种复合类型(array(),object()),2种特殊类型(null,resource)

①首先要了解,PHP是弱类型语言,即对变量类型的控制不严格。不做参数的类型检测,变量的数据类型通常不是由程序员设定的,准确的说,是PHP根据该变量使用的上下文在运

行时决定的,简单的说就是,我们不需要设定变量的数据类型,PHP会自动识别。所以这便容易产生一些数据类型上的BUG

②在强类型语言里(JAVA、C++等),会检测参数的类型,即声明变量时,前面必须加上变量的数据类型。

③在声明时,声明参数的父类类型为数字,具体实参可以是数字或数字的子类,这种现象便是多态

<?php
    class Par{//作为父类存在
    }
    class Son1 extends Par{
        public function run(){
            echo "123";
        }
    }
       class Son2 extends Par{
           public function run(){
               echo "456";
           }
       }
       function test($par){//强类型语言里参数必须声明数据类型
           $par->run();
       }
       test(new Son1());
?>

PHP是弱类型语言,不会检测数据类型,所以严格上说没有多态

 

posted @ 2018-03-25 18:06  剑仙6  阅读(187)  评论(0编辑  收藏  举报
欢迎访问个人网站www.qingchun.在线