查看: 326|回复: 0

[PHP实例] PHP面向对象详解:继承、封装与多态

发表于 2018-4-9 08:00:02

[面向对象]
1、什么是类?
具有相同属性(特征)和方法(行为)的一系列个体的集合,类是一个抽象的概念
2、什么是对象?
从类中拿到的具有具体属性值得个体,称为对象,对象是一个具体的个体

所以,面向对象即我们专注对象来处理问题,通过从一个个具有属性和功能的类中拿到对象来处理问题。

下面我们再来细说下面向对象的三大特征:继承/封装/多态

一、继承

在PHP中我们主要通关Extends关键字来实现继承 ->class Student extends Person{}

下面是几个比较重要的注意事项:

①子类只能继承父类的非私有属性。
②子类继承父类后,相当于将父类的属性和方法copy到子类,可以直接使用$this调用该属性;
PHP只能单继承,不支持一个类继承多个类。但是一个类可以进行多层继承(即A继承于B,而C又继承于A,C通过A间接继承了B)

class Person{}
   class Chengnian extends Person{}
   class Student extends Chengnian{}
  Student类就同时具有了Chengnian类和Person类的属性和方法

注意:
1.方法覆盖是指子类对继承父类中重名方法的重写或覆盖,而它的实现需要满足两个条件,一是子类继承父类;二是子类重写父类已有方法。
2.如果希望子类调用父类的构造方法,或者其他方法(public / protected),可以使用类名::方法名; 或者parent::方法名;
Class A {
public $n1=90;

  1. public function __construct() {
  2. echo "A的构造方法";
  3. }
复制代码

}

Class B extends A {
function construct() {
echo "B的构造方法";
//调用父类的两种方法
//A::
construct(); 直接用类名引用也可以同样效果
parent::__construct();
}
}
$b = new B();
页面输出:
B的构造方法A的构造方法
3.protected属性和方法受保护,在子类不能直接调用,要在子类中定义方法访问。

二、封装
类实现封装是为了不让外面的类随意的修改一个类的成员变量,所以在定义一个类的成员的时候,我们使用private关键字设置这个成员的访问权限

只能被这个类的其他成员方法调用,而不能被其他类中的方法调用,即通过本类中提供的方法来访问本类中的私有属性。

①所以在该类中我们会提供一个访问私有属性的方法

②然后我们一般会定义两个方法来实现对一个变量的操作,即:get()与set()方法。
在PHP中,封装可以用三个字来概括:私有化。具体来说,是通过访问修饰符,将类中不需要外部访问的属性和方法进行私有化处理,来实现访问控制。
封装的作用主要有两点,一是方法封装,即将使用者关注的功能暴露,而隐藏其他使用者用不到的功能;二是属性封装,即对用户的数据进行控制,防止不合法的数据传输设置。

对于方法的封装,我们通过对方法前加private关键字来进行设置,即进行私有化处理。demo如下:
private function formatName(){} // 这个方法仅仅能在类内部使用$this调用

  1. function showName(){
  2. $this -> formatName();
  3. }
复制代码

 对于属性的封装,我们可以有两种方法来进行实现。
第一种,是通过自己提供的set/get方法来对私有化的属性进行设置/读取。demo如下:

  1. private $age;
  2. function setAge($age){
  3. $this -> age = $age;
  4. }
  5. function getAge(){
  6. return $this -> age;
  7. }
复制代码

第二种,是通过魔术方法来进行实现。demo如下:

  1. private $age;
  2. function __get($key){
  3. return $this -> $key;
  4. }
  5. function __set($key,$value){
  6. $this -> $key = $value;
  7. }
复制代码

$对象 -> age; >>> 访问对象私有属性时,自动调用get()魔术方法,并且将访问的属性名传给get()方法;
$对象 -> age = "11"; >>> 设置对象的私有属性时,自动调用set()魔术方法,并且将设置的属性名以及属性值传给set()方法;

此外,有关封装的魔术方法主要有以下几种:

   ① set():给类私有属性赋值时自动调用,调用时给对象传递两个参数,需要设置的属性名、属性值
   ②
get():读取类私有属性时自动调用,调用时给方法传递一个参数,需要读取的属性名
  ③ isset():外部使用isset()函数检测私有属性时,自动调用。
  >>>类外部使用isset()检测私有属性,默认是检测不到的。即false
  >>>所以,我们可以使用
isset()函数,在自动调用时,返回内部检测结果。
   function isset($key){
    return isset($this->$key);
  }
   当外部使用isset($对象名->私有属性)检测时,将自动调用上述
isset()返回的结果!
   ④ __unset():外部使用unset()函数删除私有属性时,自动调用。

function __unset($key){
  unset($this->$key);
}

   当外部使用unset($对象名->私有属性)删除属性时,自动将属性名传给__unset(),并交由这个魔术方法处理。

实例1.

class Person{
private $name;
private $age;

  1. public function __construct($name,$age){
  2. $this->name = $name;
  3. $this->age = $age;
  4. }
  5. function setAge($age){
  6. if($age>=0&&$age<=120){
  7. $this->age = $age;
  8. }else{
  9. error_log("年龄设置有误!");
  10. }
  11. }
  12. function getAge(){
  13. return $this->age;
  14. }
  15. public function say(){
  16. echo "我叫{$this->name},我今年{$this->age}岁了";
  17. }
  18. function __get($name){
  19. switch ($name) {
  20. case 'name':
  21. return $this ->$name."这是读取时加的文字";
  22. case 'age':
  23. return "0".$this ->$name;
  24. default:
  25. return $this ->$name;
  26. }
  27. }
  28. function __set($key,$value){
  29. if($key=="name"){
  30. $this->$key = $value."这是设置时加的文字<br>";
  31. }else{
  32. $this->$key = $value;
  33. }
  34. }
  35. function __isset($name){
  36. return isset($this->$name);
  37. }
  38. function __unset($name){
  39. if($name=="age"){
  40. return;
  41. }
  42. unset($this->$name);
  43. }
  44. }
  45. $zhangsan = new Person("zhangsan",14);
  46. $zhangsan->setAge(12);
  47. echo $zhangsan->getAge()."<br>";
  48. var_dump(isset($zhangsan->name));
  49. unset($zhangsan->age);//不能unset掉私有属性
  50. echo $zhangsan->age;
复制代码
三、多态
一个类,被多个子类继承,如果这个类的某个方法,在多个子类中,表现出不同的功能,我们称这种行为为多态。(同一个类的不同子类表现出不同的形态)

那么我们如何来实现多态呢?

子类继承父类 ->子类重写父类方法 ->父类引用指向子类对象

  1. abstract class Person{ 注:父类使用abstract关键字修饰
  2. abstract function say();
  3. }
  4. class Chinese extends Person{ 注:子类重写父类方法
  5. function say(){
  6. echo "我是中国人<br>";
  7. }
  8. }
  9. class English extends Person{ 注:子类重写父类方法
  10. function say(){
  11. echo "我是英国人";
  12. }
  13. }
  14. $zhangsan = new Chinese();
  15. $zhangsan->say();
  16. $z = new English();
  17. $z->say();
  18. Person $p = new Chinese(); 注:父类引用指向子类对象
复制代码

上述代码中,两个子类都是继承自同一父类,但因为都重写了父类的方法,表现出了不同的形态

扩展:

单例设计模式

单例模式也叫单态模式
可以保证一个类只能有一个对象实例
实现要点:
①构造函数私有化,不允许使用new关键字创建对象。
②对外提供获取对象的方法,在方法中判断对象是否为空,如果为空则创建对象并返回,如果不为空则直接返回
③实例对象的属性以及获取对象的方法必须都是静态的。
④之后,创建对象只能使用我们提供的静态方法。

  1. class Singleton{
  2. static public $Single = null;
  3. private function __construct(){}
  4. static function getSingle(){
  5. if(!self::$Single){
  6. self::$Single = new Singleton();//self代指类名 new Singleton()和 newself()是完全一样的
  7. }
  8. return self::$Single;
  9. }
  10. function __destruct(){
  11. echo "我被销毁了<br>";
  12. }
  13. }
  14. $s1 = Singleton::getSingle();
  15. $s1 = Singleton::getSingle();
  16. $s1 = Singleton::getSingle();
复制代码

输出:我被销毁了

文章来源(http://www.cnblogs.com/adaia/p/6986576.html)
(https://www.cnblogs.com/wk1102/p/6986483.html)



回复

使用道具 举报