系统学习PHP之面向对象(上)

自 PHP 5 起完全重写了对象模型以得到更佳性能和更多特性。这是自 PHP 4 以来的最大变化。PHP 5 具有完整的对象模型。PHP 5 中的新特性包括访问控制,抽象类和final类与方法,附加的魔术方法,接口,对象复制和类型约束。

PHP 对待对象的方式与引用和句柄相同,即每个变量都持有对象的引用,而不是整个对象的拷贝。

1

基本概念

每个类的定义都以关键字class开头,后面跟着类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。类名可以是任何非 PHP保留字的合法标签。一个合法类名以字母或下划线开头,后面跟着若干字母,数字或下划线。一个类可以包含有属于自己的常量,变量(称为“属性”)以及函数(称为“方法”)。

Example #1 简单的类定义

当一个方法在类定义内部被调用时,有一个可用的伪变量$this。$this是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。

Example #2$this伪变量的示例

以上例程会输出:

$this is defined (A)$this is not defined.$this is defined (B)$this is not defined.

2

new

要创建一个类的实例,必须使用new关键字。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个异常。类应在被实例化之前定义(某些情况下则必须这样)。

如果在new之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。

Example #3 创建一个实例

在类定义内部,可以用new self和new parent创建新对象。

当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。此行为和给函数传递入实例时一样。可以用克隆给一个已创建的对象建立一个新实例。

Example #4 对象赋值

以上例程会输出:

NULLNULLobject(SimpleClass)#1 (1) { ["var"]=> string(30) "$assigned will have this value"}

3

extends

一个类可以在声明中用extends关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类。

被继承的方法和属性可以通过用同样的名字重新声明被覆盖。但是如果父类定义方法时使用了final,则该方法不可被覆盖。可以通过parent::来访问被覆盖的方法或属性。

当覆盖方法时,参数必须保持一致否则 PHP 将发出E_STRICT级别的错误信息。但构造函数例外,构造函数可在被覆盖时使用不同的参数。

Example #6 简单的类继承

以上例程会输出:

Extending classa default value

也就是说,调用的方法displayVar()来源于子类ExtendClass;

4

属性

类的变量成员叫做“属性”。属性声明是由关键字public,protected或者private开头,然后跟一个普通的变量声明来组成。属性中的变量可以初始化,但是初始化的值必须是常数,这里的常数是指 PHP 脚本在编译阶段时就可以得到其值,而不依赖于运行时的信息才能求值。

在类的成员方法里面,可以用->(对象运算符):$this->property(其中property是该属性名)这种方式来访问非静态属性。静态属性则是用::(双冒号):self::$property来访问。当一个方法在类定义内部被调用时,有一个可用的伪变量$this。$this是一个到主叫对象的引用(通常是该方法所从属的对象,但如果是从第二个对象静态调用时也可能是另一个对象)。

Example #1 属性声明

跟heredocs不同,nowdocs可在任何静态数据上下文中使用,包括属性声明。 Nowdoc 支持是在 PHP 5.3.0 新增的。

5

类常量

可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用$符号。

常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。

接口(interface)中也可以定义常量。自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字(如self,parent或static)。

Example #1 定义和使用一个类常量

6

类的自动加载

在编写面向对象(OOP) 程序时,很多开发者为每个类新建一个 PHP 文件。 这会带来一个烦恼:每个脚本的开头,都需要包含(include)一个长长的列表(每个类都有个文件)。

在 PHP 5 中,已经不再需要这样了。spl_autoload_register()函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。

Example #1spl_autoload_register()作为__autoload()函数的替代

Tip :尽管__autoload()函数也能自动加载类和接口,但更建议使用spl_autoload_register()函数。spl_autoload_register()提供了一种更加灵活的方式来实现类的自动加载(同一个应用中,可以支持任意数量的加载器,比如第三方库中的)。因此,不再建议使用__autoload()函数,在以后的版本中它可能被弃用。

7

构造函数

PHP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。

Note:如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。

Example #1 使用新标准的构造函数

为了实现向后兼容性,如果 PHP 5 在类中找不到__construct()函数并且也没有从父类继承一个的话,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为__construct()的方法却被用于其它用途时。

与其它方法不同,当__construct()被与父类__construct()具有不同参数的方法覆盖时,PHP 不会产生一个E_STRICT错误信息。

自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。

8

析构函数

PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。

Example #3 析构函数示例

和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。

析构函数即使在使用exit()终止脚本运行时也会被调用。在析构函数中调用exit()将会中止其余关闭操作的运行.

9

访问控制(可见性)

对属性或方法的访问控制,是通过在前面添加关键字public(公有),protected(受保护)或private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问。被定义为受保护的类成员则可以被其自身以及其子类和父类访问。被定义为私有的类成员则只能被其定义所在的类访问。

类属性必须定义为公有,受保护,私有之一。如果用var定义,则被视为公有。

end

编辑 /排版:atong

内容收集:atong

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180227G0U9GK00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券