zoukankan      html  css  js  c++  java
  • 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:PHPTutorialdemo1.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:PHPTutorialdemo1.php"
      ["line":protected]=>
      int(7)
      ["trace":"Exception":private]=>
      array(1) {
        [0]=>
        array(4) {
          ["file"]=>
          string(24) "C:PHPTutorialdemo1.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
    ame1Test();

    所以,上例可以改为

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

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

    上例继续修改

    one.php:

    use 
    ame1Test1;
    new Test1();

    two.php:

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

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

    use 
    ame1Test as newName;
    new newName();//直接new()别名

    这样便可以访问

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

    one.php:

    use 
    ame1one	wo	hreeTest as newName;
    new newName();

    two.php:

    <?php
        namespace name1one	wo	hree;
    ?>

    注意:

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

    ③引入其他页面后,自身空间不受干扰;④如果想明确使用某空间下的类,可以从根目录下逐层寻找读取,原理类似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是弱类型语言,不会检测数据类型,所以严格上说没有多态

  • 相关阅读:
    Broadcasting
    TensorFlow2-维度变换
    TensorFlow2教程(目录)
    SQL Server 加密层级
    Windows 打开防火墙上的指定端口
    SQL Server 查看对象之间的引用关系
    SQL Server 查看实例配置情况的 2 方法
    Linux 快捷键
    MYSQL 二进制日志
    SQL Server 存储过程自启动
  • 原文地址:https://www.cnblogs.com/fightjianxian/p/8645759.html
Copyright © 2011-2022 走看看