PHP基础--OOP(1)

一、类的声明--基本语法

<?php
    //声明类
    [修饰符] class 类名 [extends 父类名称] [implements 接口1名称,接口2名称]{
        //声明成员变量
        [public][var][private][protected][static][final] $变量名;

        //声明成员方法
        [public][private][protected][static][final][abstract] function 方法名(参数1,参数2){
            
        }
    }

    //实例化对象
    $引用变量名 = new 类名;    //PHP允许不加括号
    $引用变量名 = new 类名(实参1,实参2...);

    //访问对象的成员变量(不需要$符号)
    $引用变量名 -> 成员变量名称

    //给对象的成员变量赋值
    $引用变量名 -> 成员变量名称 = [值];

    //访问对象的成员方法
    $引用变量名 -> 成员方法名();
    $引用变量名 -> 成员方法名(实参1,实参2...);
    
    

 


二、对象的存储原理(开辟内存空间)

  • 栈内存的特点:空间小,与CPU的数据交换快,适合存定长的数据类型(定长不是指固定长度,而是该数据类型是固定长度,不会变化),先进后出
  • 堆内存的特点:空间大,与CPU的数据交换慢,存变长的数据类型(数组,字符串等)

所以一般通过栈内存里的引用访问堆内存的内容

 


三、$this关键字

对象中的成员方法访问对象内部的成员属性时,使用$this。

$this指代“本对象”

 


四、构造方法和析构方法

作用:初始化成员属性。

构造方法是实例化对象后,第一个自动调用的方法。

构造方法名称和类名一致。

如果以下两种构造方法同时使用,则优先使用魔术方法(php5版开始)

  • 和类名相同的方法为构造方法(不限大小写)
  • 或魔术方法__construct(),不能加private修饰词

在java中,同名构造方法或者方法可以有多个,根据参数类型和参数个数自动判断调用哪个(java的重载)。但php不支持重载,不能有多个同名方法(包括构造方法)。

 

析构方法是对象销毁前自动调用的方法

当对象失去引用,php的垃圾回收机制自动回收,在回收前自动调用析构方法。

如果声明了多个对象,根据栈的特点,后声明的对象先执行析构方法先释放

  • 魔术方法__destruct()   //php5特性,不能加private修饰词,不能有参数

 


五、封装性://PHP5特性

1、意义:

  • 封装就是给对象的属性和方法添加访问修饰符,隐藏对象的内部细节,以达到对成员的访问控制

2、语法:

  • 修饰词public,private,protected

3、成员方法的封装:

  •  private:加上后对象不能直接调用该成员方法,但对象的其他成员可以调用它。

4、成员属性的封装:

  • private:加上后对象不能直接调用或者修改成员属性
  • 可以通过方法getXXX去获取,通过方法setXXX()去有限制的修改
  • 一般有多少个成员属性,就要写多少个set和get方法。为了更加方便,使用__get(形参)和__set(形参)魔术方法来简化。
    • __get(形参):在直接访问私有成员属性时自动调用(其他修饰词的成员不自动调用),可做到通用的get方法。

例如:当访问私有成员属性$sex时,

echo $obj->sex

      此时自动调用__get(形参)方法,其中形参为访问的该私有成员属性的变量名称,那么

function __get($pro){

      return $this->$pro;

}

  • __set(形参1,形参2):在直接设置私有成员属性(其他修饰词的成员不自动调用)时自动调用,可做到通用的set方法。

例如:当设置私有成员属性$sex时,

$obj->sex = “男”

此时自动调用__set(形参1,形参2),其中形参1为 设置的该私有成员属性的变量名称,形参2为 设置的该私有成员属性的变量值,那么

function __set($key,$value){

      this->$key = $value;

}

  • 成员属性设置为私有,并使用__get和__set魔术方法,从外部看起来可以随意的得到和设置私有成员属性,这种情况和成员属性设置为公有,不写get、set方法有何区别?前者可以在方法里对成员属性进行规范和限制,后者不能。
    • 魔术方法__set()和__get()不能封装,即,不能加修饰词private。要么不写修饰词,要么写public。
  • isset()、unset()、__isset()、__unset()的区别和联系

isset()和unset()不仅可以作用于数组,同样可作用于对象。

例如当某成员属性为var(已过时)或者public时,用isset()可以判断对象中是否存在该成员属性;当先用unset()删除对象中的该成员属性,再用isset()判断,其是不存在的、

当某成员属性为private时,用isset()判断时,其是不存在的;

  • 当使用isset()判断一个对象的私有成员属性是否存在时,自动调用__isset(参数)魔术方法,参数是属性名称
  • 当使用unset()删除对象的成员属性时,自动调用__unset($参数)魔术方法,参数是属性名称
<?php
    $p = new Person("zjs",18,"male");
    isset($p->name);
    unset($p->name);

    class person{
        private $name;
        private $age;
        private $sex;

        function __construct($name="",$age=0,$sex="male"){
            $this -> name = $name;
            $this -> age  = $age;
            $this -> sex  = $sex;
        }

        function __isset($key){
            if($key=="age")
                return false;
            return isset($this->$key);
        }

        function __unset($key){
            if($key!="age")
                unset($this->$key);
        }
    }

 


六、继承性:

1、意义&介绍:

  • 子类使用extends关键字继承父类,子类可以使用父类属性和方法。
  • 开发原则:当多个类出现重复方法和属性时,抽象共性为父类。在扩展时以继承父类的方式实现,不会引发连锁反应。
  • 父类=基类,子类=派生类
  • PHP和JAVA一样是单继承,一个类只能有一个父类,但一个类可以有多个子类。

2、继承语法&权限控制:

当成员方法和成员属性都是公有时:

class Person{
    public $name;
    public $age;
    public $sex;

    function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }

    function say(){
        echo $this -> name."正在说话...";    
    }
    
    function eat(){
        echo $this -> name."正在吃饭...";    
    }
}

class Student extends Person{
    public $student_id;

    function study(){
        echo $this -> name."正在学习...";    
    }
}

class Teachere extends Person{
    public $teacher_id;

    function teach(){
        echo $this -> name."正在教学...";    
    }
}

$student1 = new Student("zjs",18,"male");
echo $student1 -> name;
//输出 zjs
$student1 -> say();
//输出 zjs正在说话...

$student1 -> study();
//输出 zjs正在学习...



当成员属性为私有,成员方法为公有时:

class Person{
    private $name;
    private $age;
    private $sex;

    function __construct($name,$age,$sex){
        $this -> name = $name;
        $this -> age = $age;
        $this -> sex = $sex;
    }

    function say(){
        echo $this -> name."正在说话...";    
    }
    
    function eat(){
        echo $this -> name."正在吃饭...";    
    }
}

class Student extends Person{
    public $student_id;

    function study(){
        echo $this -> name."正在学习...";    
    }
}

class Teachere extends Person{
    public $teacher_id;

    function teach(){
        echo $this -> name."正在教学...";    
    }
}

$student1 = new Student("zjs",18,"male");
echo $student1 -> name;
//报错:PHP Notice:  Undefined property: Students::$name in /usercode/file.php on line 39
//不能访问父类的私有成员属性

$student1 -> say();
//输出 zjs正在说话...
//可以访问父类的公有成员方法,通过父类的成员方法可以使用父类的私有成员属性name

$student1 -> study();
//报错,输出以下:
//正在学习...
//PHP Notice:  Undefined property: Students::$name in /usercode/file.php on line 26
//可以访问自己的成员方法,但成员方法不能使用父类的私有成员属性

由此可知,当父类的成员属性为私有时,子类中不能直接访问该成员属性

                  当父类的成员属性为公有时,子类中可以直接访问该成员属性

                  当父类的成员方法为私有时,子类中不能直接使用该成员方法

                  当父类的成员方法为公有时,子类中可以直接使用该成员方法

则:

                   当父类的成员属性和成员方法为公有时,这个类没有受到保护,外部可以随意访问

                   当父类的成员属性和成员方法为私有时,子类不能直接使用

如何能让类受到保护,并且能够让子类直接访问,使用呢?

  • 答案是使用关键词protected,只能自己内部和自己子类内部可以直接使用成员,而不能在外部使用。
  • 不加修饰词,或者使用public关键词,类内部,类外部,子类内部都能使用

 3、继承中的重写(不是重载):

  • 在编程语言中,重载指的是在同一个类中有多个名称相同的方法,根据参数个数和类型的不同自动选择调用的方法。
  • 因php是弱类型语言,和java不同,PHP不能重载,只能重写。
  • 重写是指:在子类中可以写和父类中同名的方法,主要是为了扩展。
  • 补充:同一类——>重载(overload),继承类——>重写(override)
  • 如果子类的某个方法不是重写的,那么在这个方法中可以使用$this->方法名()来调用从父类继承过来的所有公有方法。如果子类的某个方法是重写的,那么怎样调用父类中被重写的方法呢?不能使用$this->方法名(),$this指代的是“本类”,如果这样使用相当于是一个递归方法。正确的方法是:使用 类名::方法名调用被重写的父类方法,或者使用parent::方法名
<?php
class Person{
    protected $name;
    protected $sex;
    protected $age;
    function __construct($name="",$sex="男",$age=1){
        $this ->name = $name;
        $this ->sex = $sex;
        $this ->age = $age;
    }

    //在人类中声明一个通用的说话方法,介绍一下自己
    function say(){
        echo "我的名字:".$this-> name.",性别:".$this ->sex.",年龄:".$this ->age."。";
    }
}

class Student extends Person {
    private $school; 
    //覆盖父类中的构造方法,并在参数列表中添加一个学校属性
    //子类重写的构造方法建议调用一下父类被重写的构造方法,这样才能随父类而改变成员变量
    function __construct($name="",$sex="男",$age=1,$school=""){
        parent::__construct($name,$sex,$age);
        $this ->school = $school;
    }

    function study(){
        echo $this ->name."正在".$this ->school."学习<br>";
    }

    //定义一个和父类中同名的方法,将父类中的说话方法覆盖并重写,多说出所在的学校名称
    function say(){
        //parent::say(); 
        //或者
        Person::say();
        echo "在".$this ->school."学校上学";
    }
}


$student= new Student("张三","男",20,"edu"); 
$student -> say();

 


七、关键字介绍

1、instanceof操作符

  • 用于检测当前对象实例是否属于某一个类
<?php
class person{····}

class student extends person{····}

$p = new person();
$s = new student();

echo $p instanceof student;//false
echo $s instanceof student;//true
echo $s instanceof person;//true

2、final

  • 在php5中新增了final关键字,它只能用来修饰类和成员方法,不能定义常量,也不能修饰成员属性
  • 在java中,final是定义常量的,PHP里定义常量是用define()函数和const关键字
  • final特性:

               使用final标识的类不能有子类,不能被继承(该类不能扩展)

               使用final标识的方法不能被子类重写(该方法不能扩展)

3、static(静态)

  • 使用static修饰的成员属性在内存中被存储在初始化静态段内(见上面内存图),类的所有对象可以共用static修饰的成员属性,不再为每个对象的该成员属性单独开辟内存空间。
  • 第一次加载类的时候,就将static修饰的成员属性加载到了内存中。
  • static可以修饰成员属性和成员方法,不能修饰类
  • 静态的成员(属性和方法都是)一定要使用类来访问不能使用对象来访问。类外使用类名::成员名访问,类内使用self::成员名访问。
  • 在静态方法中不能访问非静态成员。原因:静态方法只能使用类来使用,如果其他成员非静态,那么这些成员没有开辟内存空间,即没有被创建,所以无法访问。
  • 静态成员一旦被加载,只有脚本结束后才会被释放
  • 优点:创建对象是消耗资源的,使用静态的方式可以在不创建对象的情况下直接使用,效率高,建议使用。
  • 缺点:静态成员是在类加载时开辟的内存空间,直到脚本结束才被销毁。而使用对象调用成员在脚本结束自然被销毁,另外删除对象的引用也能销毁,例如unset($obj);
<?php
class person{
    public $name = "ZJS";
    public $sex;
    public $age;
    public static $country = "中国";

    function __construct($name,$sex,$age){
        $this -> name = $name;
        $this -> sex = $sex;
        $this -> age = $age;
    }

    public function say(){
        echo "我的名字是:{$this->name},我的性别是:{$this->sex},我的年龄是:{$this->age}";
        
        //只能通过类去访问static修饰的$country
        echo "我的国家是:".self::$country;
        //或者
        echo "我的国家是:".person::$country;
    }

}

echo person::$country;//输出:中国 ,因为static修饰的成员属性$country已经被加载到内存中了

echo person::$name;    //报错,$name成员属性没有被加载到内存,只有实例化对象后才能通过对象访问

$p = new person("zjs","male",18);
echo $p->country;    //报错,只能通过类访问,不能通过对象访问

$p -> say();    //输出:我的名字是:ZJS,我的性别是:male,我的年龄是:18,我的国家是:中国

4、单态设计模式(单件、单例)

  • 目的:节约系统资源。
  • 如果想让一个类只能有一个对象,就要先让这个类不能创建对象,将构造方法私有化
  • 可以在类中使用一个静态方法来创建对象
<?php
class person{
    static $obj = null;

    private __construct(){}

    static function getObj(){

        //没有对象则创建,已有对象则直接使用上一次的创建。
        //因为static修饰的$obj是在类加载时创建的,如果脚本没有结束,保存的是上一次的值。
        if(is_null(self::$obj))
            self::$obj = new person;
            //或者
            //self::$obj = new self;
        return self::$obj;
    }
    
    function say(){
        echo "aaaaa";
    }

    function __destruct(){
        echo "#####";
    }
}

$p = person::getObj();
$p -> say();

5、const

  • JAVA使用final定义常量
  • PHP声明常量:define("常量名","常量值")
  • PHP,在类中声明常量使用const关键字,不能使用define(会报错)
  • 常量特点:值是标量类型;常量只有脚本结束才能被释放;常量值不能改变;常量存储在初始化静态段中;
  • const修饰的成员属性为常量,只能修饰成员属性。
  • 常量名建议使用大写字母,不能使用$;常量必须在声明时赋初值
  • 类中的常量的访问方式和static关键字相同。类外使用:类名::常量名;类内使用:self::常量名

 


八、魔术方法

1、__toString()

  • 在直接使用echo、print、printf输出一个对象引用时,自动调用这个方法。
  • 将对象的基本信息放在__toString()方法内部,形成字符串返回。
  • __toString()方法中,不能有参数,必须返回一个字符串
<?php
class person{
    public $name;
    public $sex;
    public $age;

    function __construct($name,$sex,$age){
        $this -> name = $name;
        $this -> sex = $sex;
        $this -> age = $age;
    }

    function say(){

    }

    function __toString(){
        return "####";
    }

}

$p = new Person("ZJS",18,"male");

echo $p;

2、__clone()克隆方法

  • 使用clone关键字克隆对象时自动调用的方法
  • __clone()的作用:类似构造方法,对克隆的对象进行初始化
  • 在这个方法中$this代表的是克隆副本
<?php
class person{
    public $name;
    public $sex;
    public $age;

    function __construct($name,$sex,$age){
        $this -> name = $name;
        $this -> sex = $sex;
        $this -> age = $age;
    }

    function say(){
        echo "我的名字是:{$this->name},我的性别是:{$this->sex},我的年龄是:{$this->age}";
    }

    function __destruct(){
        echo "{$this->name}####";
    }

    function __clone(){
        $this->name = "克隆的ZJS";
        $this->age = 0;
        $this->sex = "female";
    }

}

$p = new Person("ZJS",18,"male");

$p->say();
//输出:我的名字是:ZJS,我的性别是:male,我的年龄是:18
//      ZJS####

$p2 = clone $p;

$p2->say();
//输出:我的名字是:克隆的ZJS,我的性别是:female,我的年龄是:0
//      克隆的####

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值