PHP基础--OOP(1)

    xiaoxiao2023-11-26  156

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

    <?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)