本文要点
PHP 7为一次性对象添加了匿名类的功能,这样的例子可能是值对象以及实现了一个接口用来进行依赖注入的对象。
按照设计,匿名类是一次性使用的,不需要完整的类定义。
匿名类就像完整的类那样,可以扩展其他类、实现接口、定义构造器等等。
PHP 7引入了IntlChar类来访问Unicode字符的信息。
PHP 7废弃了一些特性,比如PHP 4风格的构造器。
在这个文章系列中,我们将会探索 PHP 7 的新特性。在第一篇文章中,我们准备好了环境并介绍了 PHP 7,随后讨论了其与面向对象编程相关的新特性。在本文中,我们会讨论 PHP 在类和接口方面的改进。
匿名类
有时候,短期使用、用后即可废弃的对象可以取代完整的类实例。
PHP 7.0 添加了对匿名类的支持,它们非常易于实例化,即便只使用一次。匿名类和完整类很相似,它们能够扩展其他的类、实现接口、定义构造器等。
作为样例,我们会创建一个匿名类来为服务器日志处理日志消息。创建一个_anonymous.php_脚本并定义包含setMsg(string $msg)
函数的LogMsg
接口,该接口允许我们设置日志消息。另外,创建一个带有 getter/setter 方法getLogMsg(): LogMsg
和setLogMsg(LogMsg $logMsg)
的 ServerLog 类,这个类用来设置服务器日志。
创建ServerLog
类的实例并调用setLogMsg(LogMsg $logMsg)
函数,其中参数是以匿名类的形式提供的。
如果运行脚本的话,var_dump
将会打印出我们传入到SetLogMsg
中的匿名类对象的引用。
object(class@anonymous)#2 (0) { }
如果在上面的样例中不使用匿名类的话,我们需要提供一个完整的实现了LogMsg
接口的类。如果不使用匿名类,相同功能的代码如下所示。
从同一个匿名类声明实例化的所有对象都是该类的实例并且彼此是完全相同的。相同比较是使用===操作符执行的,它表明要对比的对象相等并且具有相同的类型。使用===进行身份对比(identity comparison)可能一开始会让人觉得疑惑。那我们从相等操作符==开始。如果两个对象具有相同的属性和值并且是同一个类的实例,那么它们是相等的(使用==操作符进行对比)。而身份对比操作符(===)判定两个对象相同,仅在它们引用了同一个类的同一个实例时才能成立。
为了充分理解这一点,我们创建一个_anonymous-class-objects.php_脚本并定义一个返回匿名类对象的函数。现在,我们借助get_class
函数,调用这个函数两次,获取所实例化的两个不同的匿名对象,然后得到它们的类名并进行比较。如下所示,两个名字是相同的。
运行_anonymous-class-objects.php_将会生成一条输出消息,表明对象是同一个类的实例,它的名字以class@anonymous
开头。这里返回了相同的实例class@anonymousC:\PHP7.4\php-7.4-ts-windows-vc15-x64-r6c9821a\scripts\sumints.php000000000626B031
,这表明是两个相同的类。匿名类的名字是由 PHP 引擎分配的,依赖于实现。
匿名类也可以使用 extends 扩展其他的类。
为了阐述这一点,创建一个_anonymous-extend-class.php_脚本,定义带有$msg
字段及其 get/set 函数的LogMsg
类。现在,定义带有getLogMsg(): LogMsg
和setLogMsg(LogMsg $logMsg)
函数的ServerLog
类。最后,创建ServerLog
类的实例并调用setLogMsg(LogMsg $logMsg)
函数,将扩展了 LogMsg 的一个匿名类提供给LogMsg
参数:
_anonymous-extend-class.php_脚本如下所示:
运行脚本并检查输出。我们会看到LogMsg
类型的msg
字段被设置成了NULL
。
正如我们所预期的,匿名类的构造器可以传入参数。
为了阐述该功能,创建_anonymous-extend-class-add-constructor.php_脚本,并定义了像前面样例那样的LogMsg
和ServerLog
类。唯一的差异在于有个参数传递到了匿名类的构造器之中:
_anonymous-extend-class-add-constructor.php_脚本如下所示。
运行脚本并校验传递给传递给匿名类构造器的日志消息,它会被getLogMsg()
返回并打印出来。
匿名类可能会被其他类嵌套,但是它不能使用外部类的 protected 或 private 函数或属性。要想使用外部类的 private 属性,我们要像上面的例子那样将属性作为参数传递到匿名类的构造器中。
为了阐述该功能,创建一个_inner-class-private.php_脚本并定义一个外部类Outer
,它有一个私有属性。添加一个inner()
函数,该函数返回一个匿名类对象。来自Outer
类的私有属性传递到了匿名类构造器中,并设置为匿名类的 private 属性。现在,使用在匿名类中定义的函数,我们就能返回从Outer
类传递到匿名内部类的 private 属性的值:
要打印由Outer
传递给匿名内部类的 private 属性的值,我们需要创建一个Outer
类的实例并调用 inner()函数,该函数会创建匿名类,然后调用匿名类中返回 private 属性值的函数:
inner-class-private.php 脚本如下所示。
运行脚本,检查私有属性的值(1)从Outer
传递到了内部类中并打印到了浏览器上。
接下来,我们要阐述Outer
类的 protected 函数如何在匿名类中进行调用。为了调用外部类中定义的 protected 函数,匿名内部类需要扩展这个外部类。
为了阐述该功能,创建一个_inner-class-protected.php_脚本并定义名为Outer
的外部类,该类包含一个 protected 字段和 protected 函数。现在,定义另外一个函数,该函数会创建一个扩展 Outer 类的匿名类,并在匿名类中定义一个函数,让该函数调用我们最早定义的外部类的 protected 函数。因为匿名类扩展了 Outer 类,所以它继承了 Outer 类的 protected 字段和函数,这就意味着可以使用this
访问 protected 的函数和字段。和前面一样,匿名类的函数可以通过首先创建Outer
类的实例来进行调用:
_inner-class-protected.php_脚本如下所示:
运行脚本并检查Outer
类的 protected 字段以及Outer
类的函数所返回的值,如下面的输出所示。
1
2
我们使用了两个样例。分别阐述了如何从嵌入式的匿名类中调用外部类的 private 字段以及如何调用 protected 的字段与函数。我们可以将这两个样例合并到一起,让匿名的嵌套类扩展外部类,便于继承外部类 protected 的字段和函数,同时传递外部类的 private 字段到匿名类的构造器中,如下所示:
为了阐述该功能,我们创建_inner-class.php_脚本。
运行脚本将会输出 6,这是通过调用外部类的字段和函数实现的。
用于 Unicode 字符的新 IntlChar 类
PHP 7.0 引入了名为IntlChar
的新类,它提供了多个工具方法用来访问 Unicode 字符的信息。注意,要使用IntlChar
类,需要安装Intl
扩展,这可以通过在php.ini
配置文件中解除对如下代码行的注释来实现:
extension=intl
IntlChar 类中的一些方法如下表所示。
IntlChar 类的方法
我们现在创建一个_Intlchar.php_脚本来测试其中的一些方法。在如下的样例中,我们通过 IntlChar::UNICODE_VERSION
常量输出 unicode 的版本,探查LATIN CAPITAL LETTER B
的 unicode 代码点,并检查\u{00C6}
是否已定义。脚本_Intlchar.php_如下所示。
运行脚本将会产生如下的输出:
废弃的特性
PHP 7 还废弃了一些特性。
在 PHP 7.0.x 废弃的属性中,包括 PHP 4、“老式”风格的构造器,也就是构造器方法和类的名字是相同的。
举例来讲,创建 constructor.php 脚本并复制如下的代码清单到文件中。
脚本声明了一个Catalog
类,并且带有一个名称同样为Catalog
的方法。运行脚本将会看到如下的输出:
**Deprecated**: Methods with the same name as their class will not be constructors in a future version of PHP; Catalog has a deprecated constructor
除此之外,在 PHP 7.0.0 中,以静态方式调用非静态方法也被废弃了。我们创建一个 static.php 脚本并复制如下的代码清单到文件中,我们声明了一个带有非静态函数getTitle()
的类,现在尝试对这个函数进行静态调用:
运行脚本将会看到输出如下的消息:
**Deprecated**: Non-static method Catalog::getTitle() should not be called statically
在 PHP 7.1.x 中,mcrypt
扩展被废弃了。PHP 7.2 废弃的特性包括unquoted strings
、__autoload()
方法、create_function()
、强制转换为unset
、不带第二个参数使用parse_str()
、gmp_random()
函数、each()
函数、带有字符串参数的assert()
以及read_exif_data()
函数。PHP 7.3 废弃的特性包括大小写不敏感的常量以及在命名空间中声明assert()
。
作为阐述废弃大小写不敏感常量的样例,运行如下的样例,其中define()
在调用的时候,将case_insensitive
参数设置成了 true:
这将会输出如下的消息:
Deprecated: define(): Declaration of case-insensitive constants is deprecated on line 2
int(10)
Deprecated: Case-insensitive constants are deprecated. The correct casing for this constant is "CONST_1" on line 4
小结
在关于 PHP 7 系列的第二篇文章中,我们探讨了类和接口方面的新特性。最值得关注的新特性就是支持匿名类。通过一个新的类 IntlChar, Unicode 也得到了提升,该方法可以用来获取关于 Unicode 字符的信息。
在下一篇文章中,我们将会探讨 PHP 类型系统方面的新特性。
作者介绍:
Deepak Vohra 是一位 Sun 认证的 Java 程序员和 Sun 认证的 Web 组件开发人员。Deepak 在 WebLogic Developer’s Journal、XML Journal、ONJava、java.net、IBM developerWorks、Java Developer’s Journal、Oracle Magazine 和 devx 上都发表过 Java 和 Java EE 相关的技术文章。Deepak 还出版过五本关于 Docker 的书,他是 Docker 导师。Deepak 还发表了多篇关于 PHP 的文章,以及一本面向 PHP 和 Java 开发人员的 Ruby on Rails 图书。
原文链接:
Classes and Interfaces Improvements
相关阅读:
评论 1 条评论