PHP 类和对象

214 阅读4分钟

1. 概念

    1.1. 类是抽象的概念,对象是具体的实例

    1.2. 类拥有属性和方法,类的属性和方法统称为类的成员

    1.3. 面向对象的基本思路

  • 识别对象
  • 识别对象的属性
  • 识别对象的行为

    1.4. 面向对象的基本原则

  • 对内是高内聚的
  • 对外是低耦合的

    1.5. 面向对象的特性:封装、继承、多态

2. 类

2.1. 类的定义

class 类名
{
      // 定义属性
      访问控制 $属性名;
      访问控制 $属性名 = 属性值;

      // 定义方法
      访问控制 function 方法名()
      {
            ……
      }
}
  • 类名必须遵守标识符的命名规则
  • 类名中的每个单词以大写字母开头

2.2. 类的继承

class 子类名 extends 父类名
{
      ……
}
  • 类的继承是单继承,一个子类只能继承自一个父类
  • 子类会继承父类所有公有的和受保护的属性和方法

3. 对象

3.1. 对象的创建

$对象名 = new 类名(实参列表);
  • 实参列表对应构造方法的形参列表

3.2. 对象的引用

$对象名1 = &$对象名;
  • 对象名1对象名1 和 对象名 是对象的同一个引用
$对象名2 = $对象名;
  • 对象名2对象名2 和 对象名 是对象的两个不同的引用

3.3. 对象的销毁

3.3.1. 显式销毁对象

unset($对象名);

3.3.2. 隐式销毁对象

3.3.2.1. 对象的所有引用都被删除

3.3.2.2. PHP 代码执行完毕

4. 访问控制

4.1. 分类

public:公有的,可以在任何地方访问

protected:受保护的,可以在当前类及其父类、子类中访问

private:私有的,可以在当前类中访问

4.2. 注意

4.2.1. 属性必须设置访问控制

4.2.2. 用 var 定义的属性是公有的

4.2.3. 方法如果没有设置访问控制,则默认是公有的

4.2.4. 静态属性和静态方法如果没有设置访问控制,则默认是公有的

5. 属性和方法

5.1. 属性和方法

5.1.1. 概念

属性是类中的变量,方法是类中的函数

5.1.2. 定义

访问控制 $属性名 = 属性值;

访问控制 function 方法名()
{
      ……
}

5.1.3. 访问

$对象名->属性名

$对象名->方法名()

5.1.4. 注意

5.1.4.1. 属性值必须是常量

5.1.4.2. 在方法中,可以访问属性和方法,也可以访问静态属性和静态方法

5.1.4.3. 在方法中,可以用 $this 访问当前类的属性和方法

$this->属性名

$this->方法名()

5.1.4.4. 在方法中,可以用 self 访问当前类的属性和方法

self::属性名

self::方法名()

5.1.4.5. 在方法中,可以用 parent 访问父类被重写的属性和方法

parent::属性名

parent::方法名()

5.2. 静态属性和静态方法

5.2.1. 概念

5.2.1.1. 静态属性和静态方法是类的属性和方法

5.2.1.2. 静态属性和静态方法不依赖于对象而存在

5.2.2. 定义

访问控制 static $静态属性名 = 静态属性值;

访问控制 static function 静态方法名()
{
      ……
}

5.2.3. 访问

类名::$静态属性名

类名::静态方法名()

5.2.4. 注意

5.2.4.1. 静态属性值必须是常量

5.2.4.2. 在静态方法中,可以访问静态属性和静态方法,但是不能访问属性和方法

5.2.4.3. 在静态方法中,可以用 self 访问当前类的静态属性和静态方法

self::$静态属性名

self::静态方法名()

5.2.4.4. 在静态方法中,可以用 parent 访问父类被重写的静态属性和静态方法

parent::$静态属性名

parent::静态方法名()

6. 构造方法和析构方法

6.1. 构造方法

void __construct(mixed 形参列表)
  • 创建对象时,会自动调用构造方法
  • 构造方法用于初始化对象的属性
  • 构造方法的形参列表对应创建对象时的类名后面的实参列表

6.2. 析构方法

void __destruct(void)
  • 销毁对象时,会自动调用析构方法
  • 析构方法用于释放对象占用的资源

7. 重写

    7.1. 子类重新定义父类的属性或方法,称为重写

    7.2. 重写的属性和方法不能使用比原来的属性和方法更严格的访问控制

    7.3. 重写的方法的参数或返回值可以与原来的方法不同

8. final 关键字

    8.1. 被定义为 final 的类不能被继承

final class 类名
{
      ……
}

    8.2. 被定义为 final 的方法不能被重写

final 访问控制 function 方法名()
{
      ……
}

    8.3. 属性不能被定义为 final

9. 类常量

9.1. 定义

const 常量名 = 常量值;

9.2. 访问

类名::常量名

$对象名::常量名

9.3. 注意

9.3.1. 类常量可以继承

9.3.2. 类常量不能重写\

10. 接口

10.1. 概念

一个接口有多种不同的实现,这种特性称为多态

10.2. 接口的定义

interface 接口名
{
    // 声明方法
    public function 方法名(形参列表);
}
  • 接口中的方法只需要声明,不需要实现
  • 接口中声明的方法必须设置为公有的
  • 一个接口中可以声明多个方法

10.3. 接口的继承

interface 子接口名 extends 父接口名1, 父接口名2, ……
{
    // 声明方法
    public function 方法名(形参列表);
}
  • 一个子接口可以继承多个父接口

10.4. 接口的实现

class 类名 implements 接口名1, 接口名2, ……
{
    ……
    // 实现方法
    public function 方法名(形参列表)
    {
        方法体
    }
    ……
}
  • 一个类可以实现多个接口
  • 类中必须实现接口中声明的所有方法
  • 类中实现的方法和接口中声明的方法的参数必须完全一致

11. 抽象类

11.1. 概念

11.1.1. 至少有一个方法是抽象方法的类是抽象类

  • 抽象类中可以没有抽象方法
  • 有抽象方法的类必须是抽象类

11.1.2. 抽象类不能实例化对象

11.2. 抽象类的定义

abstract class 抽象类名
{
      ……
      // 声明抽象方法
      abstract 访问控制 function 抽象方法名(形参列表);
      ……
}
  • 抽象方法只需要声明,不需要实现
  • 抽象类中也可以定义普通的方法

11.3. 抽象类的继承

class 类名 extends 抽象类名
{
      ……
      // 实现抽象方法
      访问控制 function 抽象方法名(形参列表)
      {
          方法体
      }
      ……
}
  • 类继承抽象类,类中必须实现抽象类中的所有抽象方法
  • 类中实现的抽象方法不能使用比抽象类中声明的抽象方法更严格的访问控制
  • 类中实现的抽象方法和抽象类中声明的抽象方法的参数必须一致;类中实现的抽象方法也可以另外增添一些可选参数

12. 魔术方法

12.1. 概念

魔术方法的方法名以 __ 开头

12.2. 对象作为字符串使用

public string __toString(void)
  • 当对象被当作字符串使用时,会自动调用 __toString() 方法

12.3. 对象作为函数使用

public mixed __invoke([mixed 参数, ……])
  • 当对象被当作函数使用时,会自动调用 __invoke() 方法

13. 重载

13.1. 概念

13.1.1. 重载是指动态地创建属性或方法,是通过魔术方法来实现的

13.1.2. 当访问未定义或不可见的属性或方法时,会自动调用重载方法

13.1.3. 重载方法必须设置为公有的

13.2. 属性重载

13.2.1. 设置属性

public void __set(string 属性名, mixed 属性值)
  • 当设置未定义或不可见的属性的值时,会自动调用 __set() 方法

13.2.2. 获取属性

public mixed __get(string 属性名)
  • 当获取未定义或不可见的属性的值时,会自动调用 __get() 方法

13.2.3. 判断属性是否已定义

public bool __isset(string 属性名)
  • 当调用 isset() 或 empty() 函数判断未定义或不可见的属性是否已定义时,会自动调用 __isset() 方法
  • isset() 函数的返回值和 __isset() 方法的返回值相同;empty() 函数的返回值和 __isset() 方法的返回值相反

13.2.4. 销毁属性

public void __unset(string 属性名)
  • 当调用 unset() 函数销毁未定义或不可见的属性时,会自动调用 __unset() 方法

13.2.5. 静态属性不能重载

13.3. 方法重载

13.3.1. 调用方法

public mixed __call(string 方法名, array 参数)
  • 当调用未定义或不可见的方法时,会自动调用 __call() 方法

13.3.2. 调用静态方法

public static mixed __callStatic(string 静态方法名, array 参数)
  • 当调用未定义或不可见的静态方法时,会自动调用 __callStatic() 静态方法

14. 对象的高级特性

14.1. 对象复制

$对象名1 = clone $对象名2;
  • 复制生成的对象和原来的对象的所有属性值都相等
void __clone(void)
  • 当复制对象时,复制生成的对象会自动调用 __clone() 方法

14.2. 对象比较

14.2.1. 相等

如果两个变量是同一个类的对象,且所有的属性名和属性值都相等,则两个变量相等( == )

14.2.2. 全等

如果两个变量是同一个对象的引用,则两个变量全等( === )

14.3. 对象序列化

14.3.1. 概念

对象序列化和反序列化用于存储或传输数据

14.3.2. 序列化

字符串 = serialize(对象)
  • 当对象序列化为字符串时,会自动调用 __sleep() 方法

14.3.3. 反序列化

对象 = unserialize(字符串)
  • 当字符串反序列化为对象时,会自动调用 __wakeup() 方法

14.4. 对象遍历

foreach (对象 as 属性名 => 属性值)
{
    ……
}
  • 使用 foreach 语句,可以遍历对象的所有可见属性

14.5. 判断对象是否是类或接口的实例

是否 = $对象名 instanceof 类名/接口名

15. 特性

15.1. 概念

15.1.1. 特性是为了减少类的单继承的限制

15.1.2. 特性不能实例化对象

15.2. 特性的定义

trait 特性名
{
      // 定义静态属性
      访问控制 static $静态属性名 = 静态属性值;

      // 定义静态方法
      访问控制 static function 静态方法名()
      {
            ……
      }

      // 定义属性
      访问控制 $属性名 = 属性值;

      // 定义方法
      访问控制 function 方法名()
      {
            ……
      }

      // 声明抽象方法
      abstract 访问控制 function 抽象方法名();
}
  • 特性中可以定义静态属性、静态方法、属性、方法,也可以声明抽象方法

15.3. 特性的使用

15.3.1. 特性使用特性

trait 特性名
{
      use 特性名1, 特性名2, ……;
}
  • 一个特性可以使用多个特性

15.3.2. 类使用特性

class 类名
{
      use 特性名1, 特性名2, ……;

      // 实现抽象方法
      访问控制 function 抽象方法名()
      {
            ……
      }
}
  • 一个类可以使用多个特性
  • 对于同名的成员,子类中的成员会覆盖特性中的成员,特性中的成员会覆盖父类中的成员

16. 后期静态绑定

self::静态方法名()

self::方法名()

static::静态方法名()

static::方法名()
  • self 表示定义方法的类,static 表示调用方法的类

17. 自动加载

通过 spl_autoload_register() 函数注册自动加载器,当使用未定义的类或接口时可以进行自动加载

spl_autoload_register(
    function (类名或接口名)
    {
        require_once str_replace(‘\\’, ‘/’, 类名或接口名) . ‘.php’;
    }
);