一篇文章让你认识PHP中的面向对象思想

在面向对象的世界里,对象是一切的主语
关于理解都写在了注释中


<?php

header("Content-Type: text/html; charset=gb2312");
class person{
    /**
     * 成员属性
     * 在类中声明成员属性时,变量前面一定要使用一个关键字
     * 例如,public,private,static等
     * 如果不需要有特定意义的修饰,就使用var关键字
     * 如果没有任何访问控制修饰,默认的就是public
     * 其中,private只有在同一个类中才能访问,protected在同一个类中和子类中可以被访问,public则是外部成员都可以访问
     */
    var $name;
    private $sex;
    private $age;
    static $count;


    function say(){
        echo "speak";
    }

    function eat($food){
        echo "eat $food";
    }

    /**
     * 成员属性age是私有成员,采用了信息隐蔽
     * 只有在对象内部成员方法中使用如果允许用户对私有属性进行赋值操作
     * 解决办法就是在对象的内部声明一些操作私有属性的公有方法,而且可以加上限制条件,避免一些非法操作
     * 因为信息隐蔽,私有成员不能对外“公布”,但是可以通过在类中创建一个公有接口,实现功能
     * 与上面不同的是,如果是public属性,外部可以随意更改,包括一些非法操作
     */
    function setsex($age){
        if ($age>150||$age<0)
            return ;
            $this->age=$age;
    }



    //构造方法
    function  __construct($name="",$sex="男",$age=40){
        $this->name=$name;
        $this->sex=$sex;
        $this->age=$age;
        self::$count++;//测试对象被创建过多少次
        //如果在类的内部的成员方法中访问其他的静态成员,通常使用self的形式访问,最好不要直接使用类名称
    }

    //析构方法
    function __destruct(){
       // echo "再见".$this->name."<br>";
    }

    /*
     * 魔术方法,当外部调用对象中不存在的方法,则自动调用对象中的__call()方法。
     * 当调用对象中不存在的方法时就会出现系统报错,然后程序退出不能继续执行,这个方法可以
     * 当调动方法不存在时候执行,并可以继续向下执行。
     */
    function __call($functionName,$args){
        echo "你所调用的函数:".$functionName."(参数:";
        print_r($args);
        echo ")不存在!<br>\n";
    }

    /**
     * 魔术方法toString,当在外部直接输出对象的引用的时候调用这个方法
     */
    public function __toString(){
        return $this->age;
    }



    /**
     * 面向对象的封装性包含两个含义:
     * 1,把对象的全部成员属性和全部成员方法结合在一起,形成一个不可分割的独立单位(即对象)。
     * 2,信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界,只保留有限的对外接口使之与外部发生联系
     *
     * 如果属性没有被封装,就会别随意的赋值,甚至是非法的值,对对象进行破换
     * 现在上面的例子对age完成了封装,即定义为private,但是想要在外部完成赋值的操作,可通过在类中定义一个方法
     * 如下,对象内部声明一些操作私有属性的公有方法,而且可以增加一些自定义的限制条件
     */

    public function setAge($age){
        if($age>150||$age<0){
            return ;
        }
        $this->age=$age;
    }

    /**
     * 一般把类中的成员属性定义为private的,这更符合现实的逻辑,因为能更好的对类中的成员起到保护作用
     * 但是对成员属性的读取和赋值操作是非常频繁的,这时候如果在类中为每个私有的属性都定义可以在对象的外部获取和赋值的共有方法,又非常繁琐
     * 所以PHP中提供了__set(),__get(),__isset(),__unset()等预定义方法,它们都有特定的作用
     * 这些方法又叫做魔术方法,这些方法不需要我们主动调用,是当使用的时候自动调用,具体的见下面的代码
     * 可以在这些方法前面加上private关键字修饰,防止用户直接调用它,但是使用的时候报错了,提示必须使用public
     */

     /*
      * set方法,控制在对象外部只能为私有的成员属性赋值,而不能获取私有属性的值
      * 声明魔术方法需要两个参数,直接为私有属性赋值时自动调用,并可以屏蔽一些非法赋值
      */

     public function __set($propertyName,$propertyValue){
         if ($propertyName=="sex"){
             if (!($propertyValue=="男" || $propertyValue="女")){
                 return ;
             }
         }
         if ($propertyName=="age"){
             if ($propertyValue>150 || $propertyValue<0){
                 return ;
             }
            $this->$propertyName=$propertyValue;
         }
     }


     /**
      * 实现的逻辑是:
      * 返回年龄大于30自动减10返回,小于30返回真实年龄
      * 如果是要返回性别,则返回保密,其他的私有成员直接返回
      */
     public function __get($propertyName){
         if ($propertyName=="sex"){
             return "保密";
         }elseif ($propertyName=="age"){
             if ($this->age>30){
                 return $this->age-10;
             }else {
                 return $this->$propertyName;
             }
         }else {
             return $this->$propertyName;
         }
     }


     /*
      * isset()函数是用来测定变量是否存在的函数,参数是变量,返回的是布尔值
      * 那是否能用这个方法对对象中的成员属性进行测定呢
      * 如果是属性是公有的,那么可以使用这个方法,但是如果私有的,那么就被封装了,对象的属性对外部不可见
      * 这个时候就可以使用魔术方法__isset();
      * 同理,魔术方法__unset(),可以将私有成员属性删除,下面列举这两种方法
      */
       public function __isset($propertyName){
         if ($propertyName=="name"){
            return false;//限制条件,不允许在外部测定name这个属性
         }
         return isset($this->$propertyName);//其他的属性都可以被测定,并返回测定结果
     }


     public function __unset($propertyName){
         if ($propertyName=="name"){
             return ;//限制条件,不允许删除变量name,但是在本例中因为name是公有属性,所以删除属性时候不会经过这个方法,所以这个
             //逻辑实现不了,但是可以应用在其他私有成员上面
         }
         unset($this->$propertyName);
     }
}

   //下面是学生类,展示继承性,继承person类
   /*
    * 关于继承性,PHP中只支持单继承,单继承的好处是,可以降低类之间的复杂性,有更清晰的继承关系,更容易在程序中发挥继承的作用
    * 下面的子类通过extends关键字实现了继承,那么student就继承了person类中所有的属性和方法,同理teacher拥有了student的
    * 所有的属性和方法,通过继承性可以简化对象,类的创建工作量,增加了代码的可重用性。这种的优势在有很多子类的时候会被放大。
    */
   class student extends person{
       var $school;
       function study(){
           echo $this->name."正在".$this->school."学习<br>";
       }


       /*
        * 在PHP中不能定义重名函数,也包括不能在在同一个类中定义重名的方法,但是在子类中可以通过继承的方式重写父类中的方法
        * 但是如果每次都重写推翻重新写函数体,就会很麻烦,繁琐,可以使用parent::方法名,的形式在父类的基础上记性追加式的更改
        * 构造函数中也可以通过这种方式实现重载
        */
       //子类中重载父类的方法
       function say(){
           //这个时候如果在外部通过实例化teacher的对象对这个函数进行调用,返回的将会是这个函数,因为teacher中没有重写这个函数
           //但是这个重写会覆盖掉基类中的相同的函数
           parent::say();
           echo  ":i am a student...";
       }
       function __construct($name="",$sex="男",$age=40,$jinhua=54,$school="anhui"){
           parent::__construct($name,$sex,$age,$jinhua);
           $this->school=$school;
       }

   }

   class teacher extends student{
       var $wage;
       function teaching(){
           echo $this->name."正在".$this->school."教学,每月工资为:".$this->wage."。<br>";
       }
   }


   // 通过类实例化对象
  // $person1=new person();
  // $person2=new person();
   /**
    * 实例化两个对象是平行的,互不影响
    * 对象创建完成后被 存放在堆内存中,对象的引用名称是存放在栈里面的
    * 其中栈中的数据是可以直接存取的
    * 具体的原理是:使用一次new关键字就会实例化出一个对象,并在堆里开辟一块自己的空间
    * 所以可以通过对象的引用即例子中的person1等进行堆内存的空间的调用,其中对象引用中存的是堆内存的首地址
    */


    $person1->name="chandler";//通过->对类中的成员属性或者是成员方法进行访问

    $person1->age=60;

    echo $person1->name;
    echo "<br>";

    echo $person1->age;
    echo "<br>";
    echo $person1->sex;

   var_dump(isset($person1->sex));
   unset($person1->sex);
   echo "<br>";
   var_dump(isset($person1->sex));

   echo "<br>~~~~";
   var_dump(isset($person2->name));
   unset($person2->name);
   echo "<br>";
   var_dump(isset($person2->name));
   echo "<br>?????";
   $teacher1=new teacher();
   $teacher1->name="夏";
   $teacher1->school="anhuijianghuai";
   $teacher1->wage=3000;
   $teacher1->say();
   echo "<br>";
   $teacher1->study();
   echo "<br>";
   $teacher1->teaching();
   echo "<br>";
   $teacher1->say();



 /**
  *
  * 关于this
  *
  * 访问对象成员必须通过对象的引用来完成
  * 在类的外部我们可以通过new关键字创建一个对象的引用,但是如果在类内部的成员方法中时
  * 可以使用$this引用来进行访问类内存
  * 成员方法属于哪个对象,$this引用就代表哪个对象,专门用来完成对象内部成员之间的访问
  */



   /**
    *
    * 关于构造方法和析构方法
    *
    * 如果类中没有定义构造函数,PHP会自动创建一个不带参数的默认构造函数
    * 他们都与对象的生命周期有关,构造方法是对象创建完成后第一个被对象自动调用的方法
    * 而析构方法是对象在销毁之前最后一个被对象自动调用的方法
    * php5之前构造方法必须与类名相同,这种方法在5中仍然可以用,但很少了
    * 基本为__construct,而且只有一个函数,不支持重载,向下兼容,在创建对象时,如果一个类没有construct构造函数
    * PHP将搜索与类名相同名的构造方法执行
    * 不使用同名的构造方法是,更改类名的时候不需要改函数名
    *
    * 虽然不能通过使用相同的函数名实现重载,但是可以通过其他的方式实现这个功能
    * 即通过参数中赋予初值的方式,如果有初值,那么没有这个参数时候,就会使用初值
    *
    * 析构函数,关闭文件,释放结果集
    * 当堆内存段中的对象失去访问它的引用时,它就不能被访问了,成为垃圾对象,对象的引用被赋予其他值或者是页面运行结束
    * 时对象就会失去引用,当对象不能访问时,就会自动启动垃圾回收的程序,收回对象在堆中占用的内存空间
    * 而析构方法正是在回收之前调用的
    * __destruct();
    *
    * 因为栈的后进先出特点,最后创建的对象引用会被最先释放,所以调用析构函数的顺序也会遵循这一原则
    * 即先创建的对象最后被调用析构函数
    *
    */


 /**
  * 面向对象的三大特性:
  * 继承性,封装性,多态性
  */

   /**
    * 面向对象中常见的关键字和魔术方法
    * final关键字的应用
    * final关键字可以加在类或类中方法前,但不能使用final标识成员属性
    * 作用为:
    * 1,使用final标识的类,不能被继承
    * 2,在类中使用final标识的成员方法,在子类中不能被覆盖
    *
    * static关键字的应用
    * 既可以用来标识成员属性,也可以用来标识成员方法
    * 如果一个类,有成员方法test(),那么当这个类实例化很多对象的时候,每个对象都会拥有一份自己的test()属性,互不干扰
    * 但是当test前面加上static后,这个static成员总是唯一存在的,在多个对象之间共享的,因为使用static标识的成员是属于类的
    * 所以与对象实例和其他类无关,类中的静态成员不需要通过对象,而是通过类名来直接访问的,如person::$count;
    * 但是在类的内部的成员方法中的时候,通过self::$count,来进行访问
    * 上述规则适用于静态方法,但是要注意的是:
    * 在静态方法中只能访问静态成员,因为非静态成员必须通过对象的引用才能访问,通常是使用$this完成的,但是静态方法可以通过类名直接
    * 进行访问,不需要有对象,没有对象也就没有对象的引用,所以就不能访问其中的非静态成员,但是可以使用类名,或self在非静态方法中
    * 访问静态成员
    *
    * const关键字的应用
    * 在php中定义常量是通过define()函数来完成的,但是将类中的成员属性定义为常量则只能使用const关键字
    * 如:const constant='hello php';
    * 在成员方法中通过self访问常量,但注意前面不要加$符号
    *
    * clone关键字的应用
    * 如果使用new关键字重新创建对象,再为属性赋上相同的值,这样做会比较繁琐而且容易出错
    * 在php中可以根据现有的对象克隆出一个完全一样的对象,克隆之后,原本和副本两个对象完全独立互不干扰
    * 如:$p1=new person("chandler","mail",20);
    * $p2=clone $p1;
    * 如果需要为克隆后的副本对象在克隆时重新为成员属性赋初值,则可以在类中声明一个魔术方法__clone()如下:
    * function __clone(){
    *  $this->name="我是".$this->name."的副本";//其中this是本对象的引用,that是原本对象的引用
    *  $this->age=10;
    * }
    *
    *
    */

?>

关于抽象类,接口,多态的理解:

<?php

header("Content-Type: text/html; charset=gb2312");

/**
 * 下面说明接口和抽象类
 * 抽象方法是没有方法体的方法,如下:
 * abstract function fun1();
 * abstract function fun2();
 * 只要在声明类时,有一个方法是抽象方法,那么这个类就是抽象类
 * 抽象类就就像是一个半成品的类,在抽象类中还又没有被实现的抽象方法,所以抽象类不能被实例化,即创建不了对象
 * 作用是,使用抽象类就包含了继承关系,它是为它的子类定义公共接口,将它的操作,交给子类去实现
 * 定义抽象类就相当于定义了一种规范,这种规范要求子类去遵循
 */

abstract class person{
    protected $name;
    protected $country;
    function __construct($name="",$country="china"){
        $this->name=$name;
        $this->country=$country;
    }
    abstract function say();
    abstract function eat();

    function run(){
        echo "i am running!!";
    }

}

/**
 * 定义了一个类去继承抽象类,并实现抽象类中的所有的抽象方法,这样这个类就可以实例化获得对象了
 * 否则这个是将还是抽象类
 * @author 夏乐彬
 *
 */
class chineseman extends person{
    function say(){
        echo "speak chinese!";
    }
    function eat(){
        echo "chinese food is so good!!";
    }
}

/**
 * 接口技术:
 *
 * 如果说抽象类是一种特殊的类,那么接口就是一种特殊的抽象类
 * 即它所有的方法都是抽象方法,所以省去了abstract关键字
 * 不能在接口中声明变量,只能使用const关键字声明为变量的成员属性
 * 而且接口中所有成员都必须有public访问权限
 * 如果需要使用接口中的成员,则需要通过子类去实现接口中的全部抽象方法,然后创建子类的对象去进行调用
 * PHP是单继承的,一个类只能有一个父类,但是一个类可以实现多个接口
 * 像学生既要遵守国家的法律也要遵守校规,具体的形式如下:
 * class 类名 extends 类名 implements 接口一,接口二,......,接口n{
 * //实现所有接口中的抽象方法
 * }
 *
 * 使用场景:
 * 对于已经开发好的系统,在结构上进行较大的调整已经不太现实了,这时可以通过定义一些接口并
 * 追加相应的实现来完成功能结构的扩展
 */

interface one{
    const CONSTANT='CONSTANT value';
    function fun1();
    function fun2();
}

//可以通过继承接口实现接口的扩展

interface two extends one{
    function fun3();
    function fun4();
}

abstract class three implements one{
    function fun2(){
        //实现一个抽象方法
    }
}

//下面这个类将所有的抽象的方法都实现了,所以不再是抽象类
class four implements one{
    function fun1(){
        //
    }
    function fun2(){
        //具体的内容由子类决定
    }
}

/**
 * 多态性:
 *
 * 所谓的多态性就是指一段程序能够处理多种类型对象的能力
 * 在PHP中,多态性指的就是方法的重写,方法重写是指一个子类中可以重新修改父类中的某些方法,使其具有自己的特征
 * 子类重写了父类的方法,所以两个不同的对象虽然调用的都是这个方法,但返回的结果却是两个不同的信息 ,这就是多态的体现
 * 如,圆调用周长返回的是圆的周长,三角形调用返回的是三角形的周长
 * 但是圆和三角形都是继承自图形这个父类,这个方法的名称也是一样,但是返回的结果具有多态性
 * 如果想使名称一样,可以使用接口进行限制
 */

?>
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值