本章我们将继续描述 PHP 中的面向对象编程。
PHP static
关键字
我们可以将类属性和方法声明为static
。 static
属性和方法不属于该类的实例。 他们属于阶级本身。 可通过范围解析运算符::
访问它们。
staticmethod.php
在上面的 PHP 脚本中,我们有一个静态的println()
方法。 它打印一个字符串并开始新的一行。 此示例受 Java 语言启发。
我们不需要对象来调用println()
方法。 我们通过指定类名称,后跟双冒号运算符和方法名称来调用static
方法。
这是脚本的输出。
staticvariable.php
现在,我们有一个带有static
变量的示例。
我们通过指定类名,范围解析运算符和变量名来访问变量。
PHP final
关键字
最终方法不能被覆盖,最终类不能被扩展。 final
关键字取决于应用的设计。 某些类不应扩展,某些方法不应重写。 此行为由final
关键字强制执行。
finalmethod.php
该 PHP 脚本无法编译。 我们收到一个错误“无法覆盖最终方法 Base :: say()”。
finalclass.php
在先前的 PHP 脚本中,我们有一个原型基础Math
类。 该类的唯一目的是为程序员提供一些有用的方法和常量。 (出于简单起见,在我们的例子中,我们只有一种方法。)它不是为了扩展而创建的。 为了防止不知情的其他程序员从此类中派生,创建者创建了final
类。 如果您尝试运行此 PHP 脚本,则会出现以下错误:“致命错误:Class DerivedMath 可能不会从最终类(Math)继承”。
PHP 深拷贝与浅拷贝
数据复制是编程中的重要任务。 对象是 OOP 中的复合数据类型。 对象中的成员字段可以按值或按引用存储。 可以以两种方式执行复制。
浅表副本将所有值和引用复制到新实例中。 引用所指向的数据不会被复制; 仅指针被复制。 新的引用指向原始对象。 对引用成员的任何更改都会影响两个对象。
深拷贝将所有值复制到新实例中。 如果成员存储为引用,则深层副本将对正在引用的数据执行深层副本。 创建引用对象的新副本,并存储指向新创建的对象的指针。 对这些引用对象的任何更改都不会影响该对象的其他副本。 深拷贝是完全复制的对象。
在 PHP 中,我们有一个copy
关键字,默认情况下会执行浅表复制。 它调用对象的__clone()
方法。 我们可以实现创建自定义深层副本的方法。 在 PHP 中,所有对象都是通过引用分配的。
接下来的两个示例对对象执行浅复制和深复制。
shallowcopy.php
在上面的 PHP 脚本中,我们定义了两个自定义对象:Object
和Color
。 Object
对象将具有对Color
对象的引用。
我们创建 Color 对象的实例。
创建对象对象的实例。 它将 Color 对象的实例传递给其构造函数。
我们执行Object
对象的浅表副本。
在这里,我们修改克隆对象的成员字段。 我们增加 id,更改颜色对象的红色部分,并将大小更改为“大”。
我们使用print_r()
功能比较结果。
我们可以看到 ID 不同:23 与 24。大小不同:“小”与“大”。 但是,这两个实例的颜色对象的红色部分相同:255。更改克隆对象的成员值不会影响原始对象。 更改引用对象的成员也影响了原始对象。 换句话说,两个对象都引用内存中的同一颜色对象。
要更改此行为,我们接下来将做一个深层复制。
deepcopy.php
在此 PHP 脚本中,我们实现了__clone()
方法。
在__clone()
方法内部,我们复制红色,绿色和蓝色成员字段并创建一个新的 Color 对象。 现在,$color
字段指向另一个Color
对象。
现在,引用的Color
对象的红色部分不相同。 原始对象保留了其先前的 23 值。
PHP 异常
异常是为处理异常的发生而设计的,这些特殊情况会改变程序执行的正常流程。 引发或引发异常并引发异常。
在执行应用期间,许多事情可能出错。 磁盘可能已满,我们无法保存文件。 Internet 连接可能断开,我们的应用尝试连接到站点。 所有这些都可能导致我们的应用崩溃。 为避免发生这种情况,我们必须应对可能发生的所有可能的错误。 为此,我们可以使用异常处理。
从 PHP 5 开始,可以使用例外。大多数 PHP 错误仍然使用旧的错误报告,而不是例外。 使用set_error_handler()
,我们可以解决此问题。
zerodiv.php
在上面的 PHP 脚本中,我们有意将数字除以零。 这会导致错误。 该错误也不例外,并且不会被catch
关键字捕获。
set_error_handler()
功能设置用户定义的错误处理程序功能。
在set_error_handler()
函数内部,我们抛出了ErrorException
。 稍后,此异常由catch
关键字捕获。
我们正在检查错误的代码放在try
关键字之后的块中。
catch
关键字用于捕获异常。 要了解更多信息,我们在异常对象上调用getMessage()
方法。
这是我们的 PHP 脚本的输出。
Exception
是所有异常的基类。 我们可以创建派生自该基类的异常。
myexception.php
假设我们处于无法处理大量数字的情况。
大于此常量的数字在我们的 PHP 脚本中被视为“大”。
我们有一个BigValueException
类。 此类通过extends
关键字从Exception
类派生。
在构造函数内部,我们称为父级的构造函数。
如果该值大于限制,则抛出自定义异常。 我们给异常消息“超出了允许的最大值”。
我们捕获到异常并将其消息打印到控制台。
PHP 构造函数重载
PHP 不支持 Diret 构造函数重载。 换句话说,每个类只能定义一个构造函数。 许多已经知道 Java 或 C# 语言的程序员都在寻找 PHP 中的类似功能。 我们有两种方法可以处理此问题。
第一种解决方案基于func_get_args()
功能。 第二种解决方案使用工厂模式。
constructors.php
在上面的脚本中,我们有一个Book
类。 我们使用 2 和 3 参数实例化该类。
我们定义了三个成员字段。 它们的初始值为“未指定”。
func_get_args()
函数返回一个包含函数的参数列表的数组。 这样的想法是:构造函数中的代码是动态的; 它取决于传递给它的参数。
我们使用foreach
关键字浏览所有成员字段。
构造函数中最基本的任务之一是初始化类的成员字段。 这是通过上面的代码行完成的。 array_shift()
函数从数组中删除第一项并返回它。
我们有两个不同的构造函数。 第一个带有 2 个参数,第二个带有 3 个参数。
这是脚本的结果。
下一个代码示例使用工厂模式模拟构造函数重载。 它是 OOP 中的创建模式之一。 该模式创建对象时未指定要创建的对象的确切类。 更一般地,术语工厂方法通常用于指代主要目的是创建对象的任何方法。
factory.php
上面的 PHP 脚本中有一个Cat
工厂类。 它具有三种不同的静态功能。 它们每个都返回一个特定的 cat 对象。
我们有两个成员字段。 它们的初始值为“未指定”。
这是静态的withName()
函数。 此函数创建Cat
类的实例。 它设置name
成员字段并返回对象。
我们使用其中一种工厂方法创建猫的实例。 我们回荡对象,即调用该类的__toString()
方法。