首页 > 代码库 > PHP中的OOP

PHP中的OOP

【面向过程和面向对象】
 * 1、面向过程:专注于解决一个问题的过程。面向过程的最大特点,是由一个个的函数去解决处理这个问题的一系列过程;
 * 2、面向对象:专注于由哪个对象来处理一个问题。面向对象的最大特点,是由一个个具有属性和方法的功能的类,从类中拿对象,进而处理问题;
 *
 * 【面向对象】
 * 1、什么是类?
 * 具有相同属性(特征)和方法(行为)的一系列个体的集合。类是一个抽象的概念。
 *
 * 2、什么是对象?
 * 从类中拿到的具有具体属性的个体,称为对象。对象是一个具体的个体。
 *
 * 3、类和对象的关系?
 * 类是对象的抽象化,对象是类的具体化。
 * 类仅仅表明这类对象有哪些属性。但是不能有具体的值,所以类是抽象的。
 * 而对象,是将类所有属性赋值后,产生具体的个体,所以对象是具体的。

【类的声明与实例化】
  * 1、如何声明一个类?
  * class 类名{
  *  访问修饰符 $属性;
  *  [访问修饰符] function 方法(){};
  * }
  *
  * 2、声明一个类的注意事项?
  * ①类名只能有字母数字下划线组成,开头不能是数字,必须符合大驼峰法则;
  * ②类名必须使用class修饰,类名后面一定不能有();
  * ③属性必须带访问修饰符;方法可以不带访问修饰符;
  *
  * 3、实例化对象及对象属性方法的调用:
  * $对象名=new 类名();//()可带可不带;
  *
  * 类外部调用属性和方法:
  * $对象名->属性名;//使用->调用属性时,属性名不能带$符号!!
  *
  * 类内部调用属性和方法:
  * $this->属性名;
  *
  *
  * 【常见的修饰符】
  * public、protected、private、var……
  *
  * 【构造函数】
  * 1、什么是构造函数?
  * 构造函数是类中的一个特殊函数,当我们使用new关键字实例化对象时,相当于调用了类的构造函数;
  *
  * 2、构造函数有什么作用?
  * 实例化对象时,自动调用,用于给对象的属性赋初值;
  *
  * 3、构造函数的写法?
  * ①构造函数名必须与类同名:
  * [public]function Person(){
  *  $this->name=$name
  * }
  * ②使用魔术方法
  *
  * 4、构造函数注意事项:
  * ①第一种写法,构造函数名,必须与类同名!!!
  * ②如果一个类没有手写构造函数,则系统默认会有一个空参构造,因此可以使用new Person();
  *  如果我们写进了带参数的构造函数,则将不再有空参构造,也就是不能直接使用new Person();Person后面的()中的参数列表,必须符合构造函数的要求!!(即为形参实参问题);
  * ③如果两种构造函数同时存在,将使用魔术方法__construct。
  *
  * 5、析构函数:__destruct():
  * ①析构函数在对象被销毁释放之前自动调用;
  * ②析构函数不能带有任何参数;
  * ③析构函数常用于对象使用完以后,释放资源,关闭资源等;
  *
  * 6、魔术方法:
  * PHP中给我们提供了一系列__开头的函数,这些函数无需手动调用,会在合适的时机自动调用,这类函数称为魔术函数(方法);
  *  例如:function __construct(){} 在类new一个对象时自动调用;
  *     function __destruct(){} 在对象被销毁时时自动调用;
  *  我们要求,除了魔术方法之外,自定义函数与方法不能__开头;
  *
  *
  * 最后,一般对于功能比较复杂的类,我们会单独的写到一个类文件中。
  * 类文件的命名,统一小写,使用"类名.class.php"的方式命名。
  * 在其他文件中使用这个类时,使用include导入这个.class.php文件。

【继承的基础知识】 
1、如何实现继承?
 * 给子类加上extends关键字,让子类继承父类;
 *   eg: class Student extends Person{}

2、实现继承的注意事项:
 * ①子类只能继承父类的非私有属性;
 * ②子类继承父类后,相当于将父类的属性和方法copy到子类,可以直接使用$this调用该属性;
 * ③PHP只能单继承,不支持一个类继承多个类。即PHP不允许多重继承!!!
 *  但是,一个类可以进行多层继承; 
  eg:class Person{}
 *    class ChengNian extends Person{}
 *    class Student extends ChengNian{}//Student类就同时具有了Person类和ChengNian类的所有属性和方法;
 3、方法覆盖:
 * 条件①子类继承父类;
 * 条件②子类重写父类已有方法;
 *
 * 符合上述了两个条件称为方法覆盖。覆盖之后,子类调用的方法将调用子类自己的同名方法;
 *
 * 同样,除了方法覆盖,子类也可以具有与父类同名的属性,进行属性覆盖; 
 *
 * 如果子类重写了父类方法,如何在子类中调用父类的同名方法?
 * parent::方法名();
 *
 * 所以,当子类继承父类时,需在子类构造中的第一步,首先调用父类构造并进行赋值;
 *   eg:function __construct($name,$sex,$school){
    parent::__construct($name,$sex);
    $this->school=$school;
   }

【封装的基本概念】
1、什么是封装?
通过访问修饰符,将类中不需要外部访问的属性和方法进行私有化处理,以实现访问控制。
 >>>注意是实现访问控制,而不是拒绝访问。也就是说,我们私有化属性之后,需要提供对应的方法,让用户通过我们提供的方法处理属性。

2、封装的作用?
 * ①使用者只关心类能够提供的功能,而不需要关心功能实现的细节(封装方法)!
 * ②对用户的数据进行控制。防止设置不合法数据,控制返回给用户的数据(属性封装+set/get方法)!

3、实现封装操作:
 * ①方法的封装:
 * 对于一些只在类内部使用的方法,而不想对外不提供试用。那么,这样的方法我们可以使用private进行私有化处理;
 *   eg:private function say1(){
    return "我叫{$this->name},今年{$this->age}岁了!</br>";
   }
   function say(){
    echo $this->say1();
   }

②属性的封装+set/get方法:
 * 为了控制属性的设置以及读取,可以将属性进行私有化处理,并要求用户通过我们提供的set/get方法进行设置;
 *   eg:private $age;
    function setAge($age){
    if($age>=0&&$age<=99){
     $this->age=$age;
    }else{
     error_log("年龄设置有误!");
    }
   }
   function getAge(){
    return $this->age;
   }
    $对象->getAge();
    $对象->setAge(12);

③属性的封装+魔术方法;
 *    eg:private $age;
 *    function __get($key){
     switch ($key) {
      case ‘name‘:
       return $this->$key."(这是__get读取时加上的文字!)</br>";
       
      case ‘age‘:
       return $this->$key."(这是__get读取时加上的文字!)</br>";
      
      default:
       return $this->$key."(这是__get读取时加上的文字!)</br>";
       break;
     }
    
   }

function __set($key,$value){
     if($key=="name"){
      $this->$key=$value."(这是__set设置上的文字!)</br>";
     }else{
      $this->$key=$value;
     }
   }

$对象->age;//访问对象私有属性时,自动调用__get()魔术方法,并且将访问的属性名传给__get()
 * 方法;
   $对象->age=12;//设置对象私有属性时,自动调用__set()魔术方法,并且将设置的属性名以及属性值传给__set()方法 ;
 *    
 *    注意:在魔术方法中,可以使用分支结构,判断$key的不同,进行不同的操作。

4、关于封装的魔术方法:
 * ①__set($key,$value):给类私有属性赋值时自动调用,调用时给方法传递两个参数:需要设置的属性名、属性值;
 *
 * ②__get($key):读取类私有属性时自动调用,调用时给方法传递两个参数:需要读取的属性名;
 *
 * ③__isset($key):外部使用isset()函数检测私有属性时,自动调用。
 *   >>>类外部检测私有属性,默认是检测不到的。false.
 *   所以我们可以使用__isset()函数,在自动调用时,返回内部检测结果;
  eg:function __isset($name){
    return isset($this->$name);
   }
 *   当外部使用isset($对象名->私有属性);检测时,将自动调用上述__isset()返回的结果;
 *
 * ④__unset($key):外部删除私有属性是自动调用;
 *   eg:function __unset($name){
    unset($this->$name);
   }
 *   当外部使用unset($对象名->私有属性);删除属性时,自动将属性名传给__unset();,并交由这个魔术方法处理。

【关键字】
1、final:
 * ①final修饰类,此类为最终类,不能被继承;
 * ②final修饰方法,此方法为最终方法,不能被重写;
 * ③final不能修饰属性;

2、static:
 * ①可以修饰属性和方法,分别称为静态属性、静态方法,也叫类属性、类方法。
 * ②静态属性、静态方法,只能使用类名直接调用。
 *   使用“类名::$静态属性”、“类名::静态方法()”
  Person::$sex;   Person::say();
 * ③静态属性、方法,在类第一次装载时就会产生。先于对象产生;
 *
 * ④静态方法中,不能调用非静态属性或方法;非静态方法可以调用静态属性或方法;(因为静态属性和方法在类装载时就已经产生,而非静态属性方法此时还没有实例化诞生!)
 * ⑤在类中,可以使用self关键字,代指类名;
 *   eg:class Person{
    static $sex="男";
    function __construct($name,$sex){
     $this->name=$name;
     self::$sex=$sex;
    }
   } 
   echo Person::$sex;

⑥静态属性是共享的。也就是说new很多对象也是共用一个属性;

3、const关键字;
 * 在类中声明常量,不能使用define()函数!必须使用const关键字。
 * 与define()声明类似,const关键字声明不能带$,必须全部大写。
 * 常量一旦声明,不能改变。调用时与static一样,使用类名调用;Person::常量;

4、 instanceof操作符:
 * 检测一个对象,是否是某一个类的实例(包括父辈 爷爷辈……);
 * 返回布尔值;

【小总结】几种特殊操作符:
1、.只能连接字符串    ""."";
2、=>声明数组时,关联键与值;["key"=>"value"];
3、->对象(this new出的对象)调用成员属性、成员方法。
4、::①使用parent关键字,调用父类中的同名方法;parent::say()
  ②使用类名(和self),调用类中的静态属性静态方法以及常量;

PHP中的OOP