【学习:php面向对象编程】

一、类与对象

1.1 成员属性

定义:类的变量
属性的声明有: private > protected > public
数据类型:1、基本数据类型(整型int、浮点型float、字符串string、布尔bool);2、复合数据类型(数组array、对象object);3、特殊数据类型(null资源

二、构造函数

2.1 语法

// 访问修饰符:private、protected、public 默认 public
// 构造函数是创建对象时,由系统自动调用
访问修饰符 function __construct(形参列表){
    // 完成对成员属性的初始化
}

2.2 this说明

系统会给每个对象分配this,代表当前对象
this 只能在类内部方法中使用,不能在类定的的外部使用。

三、析构函数

3.1 语法

public function __destruct(){
    // 释放该对象的资源
}

定义:在到某个对象的所有引用都被删除或者当对象被显式销毁时执行,说白了就是对象调用结束前
场景:析构函数是在对象被销毁前, 给程序员一个机会,去释放该对象分配的相关资源的, 比如数据库链接, 比如你打开的文件,比如绘图的句柄

Created with Raphaël 2.1.2 PHP执行简单流程 浏览器 浏览器 Apache Apache 代码区 代码区 请求 执行 返回结果 相应

3.2 垃圾回收机制

1、php中,一个对象没有任何引用指向它时,就会成为一个垃圾对象,php将启用垃圾回收器将对象销毁
2、当程序退出前,php也会启用垃圾回收器,销毁对象

四、魔术方法

4.1 说明

1、程序员不能主动的调用魔术方法, 当满足某个条件时,系统会自动的调用魔术方法
2、魔术方法是系统给我们提供的
3、魔术方法都是以__ 开头的,因此我们自定以函数时,就不要使用__开头

4.2 方法的访问修饰符

public : 在任何地方被访问
protected : 可以被其自身以及其子类父类访问
private : 只能在该类 里面访问

4.3 魔术方法介绍

__get 和 __set

1、读取不可访问属性的值时,__get()会被调用 // 都是在类的内部定义,外部调用
2、在给不可访问属性赋值时,__set() 会被调用
3、不可访问的属性就是指这样的情况(1. 属性不存在2. 属性是protectedprivate)

    /**  
     * __get()
     * @param $get_name [string]  [你要获取的属性名,这里是protected、private才被调用]
     */
    public function __get($get_name){
        # property_exists():检查对象或类是否具有该属性
        if(property_exists($this, $get_name)){
            return $this->$get_name;//返回该类的对应属性值
        } else {
            return '没有这个属性';
        }
    }

    /**
     * __set()
     * @param $set_name [string]  [你要设置的属性名,这里是protected、private才被调用]
     * @param $set_val  [string]  [你要设置的属性值,这里是protected、private才被调用]
     */
    public function __set($set_name, $set_val){
        # property_exists():检查对象或类是否具有该属性
        if(property_exists($this, $set_name)){
            return $this->$set_name = $set_val;//返回该类的对应属性值
        } else {
            return '没有这个属性';
        }
    }

__isset 和 __unset

1、当对不可访问属性调用isset()empty()时,__isset()会被调用
2、当对不可访问属性调用 unset() 时,__unset()会被调用
3、不可访问的属性就是指这样的情况(1. 属性不存在2. 属性是protectedprivate)

__toString

当我们把一个对象当做字符串输出时,就会自动的调用__toString

__clone

当我们去克隆一个对象时,__clone 方法就会被自动的调用

__call

1、在对象中调用一个不可访问方法时,__call() 会被调用
2、注意这里的__call( string $method, array $args) 里面必须有2个参数第一个是要调用类里面的方法名,第二个是实例化该类传进来的参数
3、不可访问的属性就是指这样的情况(1. 属性不存在2. 属性是protectedprivate)
士大夫士大夫

__callStatic

1、当我们调用一个不可以访问的静态方法时,__callStatic魔术方法就会被触发
2、不可访问的方法就是指这样的情况(1. 方法不存在2. 方法是protectedprivate)

五、类的自动加载

5.1 自动加载:__autoload

创建一个类名和类文件的映射数组

    /**
     * [old]: 以前是分别引入 require() 文件
     * [now]: 现在创建一个类名和类文件的映射数组
     */
    $map = array(
        'Cat'  => './Cat.php',
        'Dog'  => './Dog.php',
        'Tiger'  => './Tiger.php',
        'Sheep'  => './Sheep.php',
        // ...  =>  ...
    );

    /**
     * 功能:当我们使用一个没有定义的类名时,该函数就会被调用
     * @param $class_name [string] [被调用的类名]
     */
    public function __autoload($class_name)  // 注意:这里使用的是php自带的__autoload()方法
    {
        # 动态引入类 $map 就是上面定义的数组,用global引入方法内使用
        global $map;
        require $map[$class_name];
    }

5.2 回调函数:spl_autoload_register

我们可以使用spl_autoload_register (回调函数) 来注册自己的自动加载函数,注意前面没有__

    /**
     * [old]: 以前是分别引入 require() 文件
     * [now]: 现在创建一个类名和类文件的映射数组
     */
    $map = array(
        'Cat'  => './Cat.php',
        'Dog'  => './Dog.php',
        'Tiger'  => './Tiger.php',
        'Sheep'  => './Sheep.php',
        // ...  =>  ...
    );

    /**
     * 功能:当我们使用一个没有定义的类名时,该函数就会被调用
     * @param $class_name [string] [被调用的类名]
     */
    public function my__autoload($class_name)   // 注意:这里使用的自定义的 my__autoload()方法
    {
        # 动态引入类 $map 就是上面定义的数组,用global引入方法内使用
        global $map;
        require $map[$class_name];
    }
    // 使用spl_autoload_register()注册[自定义]的加载函数
    spl_autoload_register('my__autoload');

六、静态属性

概念:静态属性是该类的所有对象 共享的变量 ,任何一个该类的对象去访问它时,取到的都是相同的值;同样修改它时,修改的也是同一个变量。
定义:访问修饰符 static 静态属性名

6.1 如何访问静态属性

1、在类的外部如何访问静态属性 ,必须为public

    类名::$静态属性名

2、在类的内部访问静态属性,可以是publicprotectedprivate

    第一种 ==>    类名::$静态属性名;
    第二种 ==>    self::$静态属性名;   //常用第二种,灵活

注意: self 是类的范畴(指向类),$this 是对象实例(指向对象实例)

七、静态方法

概念: 静态方法通常是用来操作静态属性的,静态方法又称类方法
定义:访问修饰符,可以是publicprotectedprivate

    访问修饰符 static function 方法名(形参列表){
        //函数体
    }

7.1 如何访问静态方法

1、在类的外部如何访问静态方法 ,必须为public

    类名::静态方法名(参数)

2、在类的内部访问静态属性,可以是publicprotectedprivate

    第一种 ==>    类名::静态方法名(参数);      // 常用第一种
    第二种 ==>    self::静态方法名(参数);  
    第三种 ==>    $this->静态方法名(参数);

7.2 注意事项

注意:1、 静态方法中不能访问 非静态属性 ;普通的成员方法,可以访问静态属性非静态属性
            2、如果我们的静态方法是protectedprivate 则也不能在类的外部使用

7.3 静态方法和静态属性的最佳实践

单例模式

八、oop编程的三大特征 – – 封装

抽象

定义: (就是将一类事物的共同特征[属性, 行为(成员方法)]提取出来,形成一个模板(类), 这种研究问题的方式就是抽象

8.1 封装

定义:是将数据(成员属性)和操作(成员方法)封装在一起,把数据保护起来的目的,如果需要操作数据,需要通过被授权的方法(通过public的成员方法)才可以实现

8.2 封装是如何实现

在php的面向对象中,是通过 访问控制符来实现封装的, 具体的说就是通过publicprotectedprivate 来实现

九、oop编程的三大特征– – 继承

概念:
1、把多个类共有的属性和方法提出来,做成一个A类(父类,基类)
2、让B、C类继承A类(extends);B、C称为子类,扩展类
3、在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法
定义:

    class  类名  extends 父类名{
          //属性,方法等等.
    }

9.1 继承细节

1、父类的 private 修饰的属性和方法,在子类中不能使用
2、承不能简单的理解成子类定义时,会把父类的属性声明,方法定义拷贝一份,而是建立了继承查找的的关系
3、子类最多只能继承一个父类(指直接继承)
4、在创建某个子类对象时,默认情况下会自动调用其父类的构造函数
5、如果在子类中需要访问其父类的方法(构造方法/成员方法 方法的访问修饰符是public/protected),可以使用 父类::方法名(或者 parent::方法名 ) 来完成
6、如果子类(扩展类)中的方法和父类(基类)方法相同,我们称为方法重写

9.2 重载

9.2.1 方法重载

所谓方法重载,是指动态的创建成员属性成员方法,在php中,是通过魔术方法来实现
这里写图片描述
                              ***************** *****************
                                                         仔细阅读
                              ***************** *****************
1、由于PHP是弱类型语言,因此函数的输入参数类型无法确定(可以使用类型暗示,但是类型暗示无法用在诸如整型,字符串之类的标量类型上)。并且对于一个函数,比如只定义了3个输入参数,PHP却运行调用的时候输入4个或者更多的参数。因此基于这2点,注定了PHP中无法重载函数,(类似Javascript语言),也无法有构造函数的重载
2、由于实现函数的重载对提高开发效率很有帮助

    /**
     * [old]以前方法重载,通过参数个数和类型不同来区分
     */
    public function index($foo1, $foo2){
        // todo...
    }
    public function index($foo1, $foo2, $foo3){
        // todo...
    }
        /**
         * [now]现在重载,通过参数个数和类型不同来区分
         */
        class A{
        public function index($foo1, $foo2){
            // todo...
        }
        public function index2($foo1, $foo2, $foo3){
            // todo...
        }

        // 使用模式方法实现 用魔术方法 __call 访问一个不存在或无权限方法时调用
        public function __call($method, $args)
        {
            // 实现处理方法,使用__call()判断参数个数
            if(count($args) == 2){
                $this->index($args[0], $args[1]);             // 调用index()
            }else if(count($args) == 3){
                $this->index2($args[0], $args[1], $args[2]);  // 调用index2()
            }
        }
    }
    $a = new A();
    $a->null_fun($num1, $num2);   // 调用一个A类不存在的方法null_fun,会触发A类中的__call方法。

9.2.2 属性重载

    /**
     * 编写一个 public 的 __set()就可以阻止属性重载
     */
    class B{
        public $color;               // 存在属性
        private $pro_arr = array();  // 存储不存在,外部传入的属性        

        public function __set($pro_name, $pro_val){
            if(!property_exists($this, $pro_name)){
                $this->pro_arr[$pro_name] = $pro_val;    // 把调用B类时传入的值赋予传入属性
            }
        }

        public function __get($pro_name)
        {
            if(isset($this->pro_arr[$pro_name])){       // 查询调用B类时传入的属性有无对应的属性
                $this->pro_arr[$pro_name];              
            }else{
                echo '属性不存在';
            }
        }

        /**
         * 这里只是为了当外部传入B类的属性后,打印出来看B类的属性
         */
        public function showAllPro()
        {
            echo '<br>动态增加的属性有 ==> ';
            foreach ($this->pro_arr as $k => $v) {
                echo '<br>属性名:' . $k;
                echo '<br>属性值:' . $v;
            }
        }

    }

    $b          = new B();
    $b->name    = '不存在名字';  // B类中不存在该属性
    $b->address = '不存在地址';  // B类中不存在该属性
    $b->color   = '存在颜色红色';// B类中存在该属性
    // 打印B类看里面属性做对比
    echo '<pre>';
    var_dump($b);

    echo '<hr>';
    $b->showAllPro();

输出结果如下

object(B)#1 (2) {
  ["color"]=>
  string(18) "存在颜色红色"
  ["pro_arr":"B":private]=>
  array(2) {
    ["name"]=>
    string(15) "不存在名字"
    ["address"]=>
    string(15) "不存在地址"
  }
}

动态增加的属性有 ==> 
属性名:name
属性值:不存在名字
属性名:address
属性值:不存在地址

关于重载,PHP中,有三种方式处理

1、使用默认机制,不去管理
2、组织开发者使用重载,很有必要
3、可以自己管理属性重载

十、oop编程的三大特征– – 多态

概念: 指的是对象在不同的情况下的多种状态, 根据面向对象时运行的上下文环境来决定

    /***************/
       // 1、动物类
    /***************/
    class Animal{
        public $name;
        public function __construct($name)
        {
            $this->name = $name;
        }
    }

    /******** 猫继承动物类 **************/
    class Cat extends Animal{
        public function showInfo()
        {
            echo '<br> Cat-猫的名字:' .$this->name;
        }
    }

    /******** 狗继承动物类 **************/
    class Dog extends Animal{
        public function showInfo()
        {
            echo '<br> Dog-狗的名字:' .$this->name;
        }
    }

    /***************/
       // 2、食物类
    /***************/
    class Food{
        public $name;
        public function __construct($name)
        {
            $this->name = $name;
        }
    }

    /******** 鱼继承食物类 **************/
    class Fish extends Food{
        public function showInfo()
        {
            echo '<br> Fish-鱼的品种:' .$this->name;
        }
    }

    /******** 骨头继承食物类 **************/
    class Bone extends Food{
        public function showInfo()
        {
            echo '<br> Bone-骨头的品种:' .$this->name;
        }
    }

    /***************/
       // 3、综合主人类
    /***************/
    class Master{
        public $name;
        public function __construct($name)
        {
            $this->name = $name;
        }

        /**
         * 喂食
         * 这里使用类型约束,当我们的类型约束使用的是类(对象),
         * 可以使用该类的对象实例和该类的子类对象实例
         */
        public function feed(Animal $animal, Food $food)
        {
            echo '<br> 主人是:' . $this->name;
            $animal->showInfo();
            echo '<br> 喜欢吃';
            $food->showInfo();
        }
    }

    $cat = new Cat('小黑猫');
    $dog = new Dog('大花狗');

    $fish = new Fish('沙丁鱼');
    $bone = new Bone('脆骨');

    $master = new Master('贝爷');

    // 用master对象喂食
    $master->feed($cat, $fish);
    echo '<hr>';
    $master->feed($dog, $bone);

输出结果


主人是:贝爷
Cat-猫的名字:小黑猫
喜欢吃
Fish-鱼的品种:沙丁鱼

--------------------------------------------------------------------------------------------
主人是:贝爷
Dog-狗的名字:大花狗
喜欢吃
Bone-骨头的品种:脆骨

十一、抽象类

概念:当程序员定义一个类,该类的一些方法不能确定,就可以将该方法做成一个抽象方法,这个类就做成一个抽象类
抽象类是用于设计的,然后需要其它的类来继承并实现抽象类
定义:1、抽象方法是在方法前使用关键字 abstract来修饰    2、抽象类是使用abstract来修饰

    abstract class 类名 {
        abstract 修饰符 function 函数名(参数列表);     //注意这里没有方法体!
    }

11.1 抽象方法细节

1、抽象类不能被实例化
2、抽象类可以没有abstract方法, 抽象类可以有非抽象方法(普通的方法), 成员属性和常量
3、一旦类包含了abstract方法,则这个类必须声明为abstract
4、抽象方法不能有函数体,即不能有{ }
5、如果一个类继承了某个抽象类,则它必须实现该抽象类的所有抽象方法.(除非它自己也声明为抽象类)[多级继承]

十二、接口

概念: 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
定义:
1、interface是一个关键字,表示后面是接口
2、接口的命名规范,iXxxxYxxx, 以i开头,然后使用大驼峰法
3、接口的方法,全部都是抽象方法,但是不能使用abstract去修饰
4、接口中可以定义常量 const 常量名 = 值
5、一个类可以同时实现多个接口,使用,号间隔即可
6、接口中可以有属性,但只能是常量 ,默认是public, 但不能public显式修饰
7、接口和接口直接可以是继承(extends)的关系,interface A extends B{ }

    interface  接口名{
        //属性
        //方法
    }

小结:

1、类和类之间是继承
2、类和接口之间是实现
3、接口和接口之间可以是继承

总结: 抽象类和接口的区别

最主要:抽象类是定义方法,但是不知道怎么实现;接口时定义方法让继承的来实现
1、对接口的继承使用implements,抽象类使用extends
2、接口中不可以声明变量,但可以声明类常量.抽象类中可以声明各种变量
3、接口没有构造函数,抽象类可以有
4、接口中的方法默认为public,抽象类中的方法可以用public,protected,private修饰
5、一个类可以继承多个接口,但只能继承一个抽象类

十三、final关键字

场景:如果我们不希望某个成员方法重写,则可以将这个方法设置成final方法,如果我们不希望某个类被继承,则可以设置成final
定义:
1、final是一个关键字,不能修改,不能修饰成员属性
2、如果一个方法被修饰成final则,该方法不能被子类重写
3、如果一个类被修饰成final,该类不能被继承
4、什么时候可能使用到,出于安全考虑,不希望其它程序员来继承或者重写重要方法,就可以使用final
5、一般来说,final类中不会出现final方法,因为final类都不能被继承,也就不会去重写override final类的方法了, 但是语法不会报错
6、final类是可以被实例化

    final  类名{
            //属性
            final 访问修饰符 成员方法名(参数列表){
            //函数体
        }
    }

猜你喜欢

转载自blog.csdn.net/hello_sgw/article/details/81028983