了解统一变量语法
PHP 7.0 中引入的最激进的举措之一是努力规范 PHP 语法。PHP 早期版本的问题在于,在某些情况下,操作是从左向右解析的,而在另一些情况下,则是从右向左解析的。这种不一致性是造成许多编程漏洞和困难的根本原因。因此,PHP 核心开发团队发起了一项名为 "统一变量语法" 的倡议。首先,让我们来定义构成统一变量语法倡议的关键点。
定义统一变量语法
统一变量语法既不是一种协议,也不是一种正式的语言结构。相反,它是一项指导原则,旨在确保以统一一致的方式执行所有操作。
以下是该倡议的一些要点:
-
变量顺序和引用的一致性
-
函数调用的一致性
-
解决数组解引用的问题
-
提供在单个命令中混合函数调用和数组解引用的能力
有关 PHP 7 统一变量语法原始提案的更多信息,请访问: https://wiki.php.net/rfc/uniform_variable_syntax 。 |
现在让我们来看看统一变量语法倡议如何影响 PHP 8。
统一变量语法如何影响 PHP 8?
统一变量语法计划在 PHP 7 的所有版本中都非常成功,过渡也相对顺利。不过,仍有一些地方没有升级到这一标准。因此,我们提出了一个新的建议来解决这些问题。在 PHP 8 中引入了以下统一标准:
-
取消引用内插字符串
-
魔术常数的取消引用不一致
-
类常量解引用的一致性
-
增强了对
new
和instanceof
的表达式支持
在逐一举例说明之前,我们必须首先明确解引用的含义。
定义解引用
解引用 是提取数组元素或对象属性值的过程。它也指获取对象方法或函数调用返回值的过程。下面是一个简单的例子:
// /repo/ch02/php7_dereference_1.php
$alpha = range('A','Z');
echo $alpha[15] . $alpha[7] . $alpha[15];
// output: PHP
$alpha
alpha 包含 26 个元素,分别代表字母 A 至 Z。本示例解引用数组,提取第 7 和第 15 个元素,产生 PHP 输出。解引用函数或方法调用简单地说就是执行函数或方法并访问结果。
解引用内插字符串
下一个示例有点疯狂,请密切关注。下面的示例在 PHP 8 中有效,但在 PHP 7 或更早版本中无效:
// /repo/ch02/php8_dereference_2.php
$alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$num = '0123456789';
$test = [15, 7, 15, 34];
foreach ($test as $pos)
echo "$alpha$num"[$pos];
在本例中,两个字符串 $alpha
和 $num
在 foreach()
循环中使用双引号进行插值。下面是 PHP 7 的输出结果:
root@php8_tips_php7 [ /repo/ch02 ]# php php7_dereference_2.php
PHP Parse error: syntax error, unexpected '[', expecting ',' or ';' in /repo/ch02/php7_dereference_2.php on line 7
Parse error: syntax error, unexpected '[', expecting ',' or ';' in /repo/ch02/php7_dereference_2.php on line 7
PHP 8 中的相同代码会产生以下输出:
root@php8_tips_php8 [ /repo/ch02 ]# php php8_dereference_2.php
PHP8
魔术常数的解引用不一致
在 PHP 7 及以前的版本中,常量可以解引用,而魔法常量则不能。下面是一个生成当前文件最后三个字母的简单示例:
// /repo/ch02/php8_dereference_3.php
define('FILENAME', __FILE__);
echo FILENAME[-3] . FILENAME[-2] . FILENAME[-1];
echo __FILE__[-3] . __FILE__[-2] . __FILE__[-1];
下面是 PHP 7 中的结果:
root@php8_tips_php7 [ /repo/ch02 ]# php php7_dereference_3.php
PHP Parse error: syntax error, unexpected '[', expecting ','
or ';' in /repo/ch02/php7_dereference_3.php on line 7
Parse error: syntax error, unexpected '[', expecting ',' or ';'
in /repo/ch02/php7_dereference_3.php on line 7
下面是 PHP 8 中的结果:
root@php8_tips_php8 [ /repo/ch02 ]# php php8_dereference_3.php
phpphp
再次强调,PHP 8 中的解引用操作应用一致(这是件好事!)。
类常量解引用一致性
在尝试解引用类常量时,会出现一个相关的问题。为了更好地说明这个问题,请假设我们有三个类。第一个类 JsonResponse
以 JavaScript Object Notation(JSON)格式生成数据,如下代码片段所示:
class JsonResponse {
public static function render($data) {
return json_encode($data, JSON_PRETTY_PRINT);
}
}
第二个类 SerialResponse
使用 PHP 内置的 serialize()
函数生成响应,如下代码片段所示:
class SerialResponse {
public static function render($data) {
return serialize($data);
}
}
最后,Test
类可以产生任一响应,如下面的代码片段所示:
class Test {
const JSON = ['JsonResponse'];
const TEXT = 'SerialResponse';
public static function getJson($data) {
echo self::JSON[0]::render($data);
}
public static function getText($data) {
echo self::TEXT::render($data);
}
}
正如您在本节前面的示例中看到的,PHP 早期版本的结果并不一致。调用 Test::getJson($data)
可以正常工作。但是,调用 Test::getText($data)
却会产生这样的错误:
root@php8_tips_php7 [ /repo/ch02 ]# php php7_dereference_4.
php PHP Parse error: syntax error, unexpected '::' (T_
PAAMAYIM_NEKUDOTAYIM), expecting ',' or ';' in /repo/ch02/php7_
dereference_4.php on line 26
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_
NEKUDOTAYIM), expecting ',' or ';' in /repo/ch02/php7_
dereference_4.php on line 26
如图所示,在 PHP 8 中使用完全相同的代码,可以对前面显示的类中定义的两个方法调用产生一致的结果:
root@php8_tips_php8 [ /repo/ch02 ]# php php8_dereference_4.php
{
"A": 111,
"B": 222,
"C": 333}
a:3:{s:1:"A";i:111;s:1:"B";i:222;s:1:"C";i:333;}
总之,在 PHP 8 中,类常量现在以统一的方式解引用,从而可以编写出更简洁的代码。现在,让我们看看 PHP 8 是如何让你在比以前更多的地方使用表达式的。
增强了对 new 和 instanceof 的表达式支持
PHP 7 编程的乐趣之一就是可以在任何地方使用任意的 PHP 表达式。在这个简单的示例中,请注意在引用 $nav
数组的方括号内使用了 $_ GET['page'] ?? 'home'
的任意表达式,该表达式位于引用 $nav
数组的方括号内:
// /repo/ch02/php7_arbitrary_exp.php
$nav = [
'home' => 'home.html',
'about' => 'about.html',
'services' => 'services/index.html',
'support' => 'support/index.html',
];
$html = __DIR__ . '/../includes/'
. $nav[$_GET['page'] ?? 'home'];
但在 PHP 7 和更早的版本中,如果表达式涉及 new
或 instanceof
关键字,则无法实现同样的功能。正如您可能已经猜到的,PHP 8 已经解决了这种不一致性。现在可以执行以下操作:
// /repo/ch02/php8_arbitrary_exp_new.php
// definition of the JsonRespone and SerialResponse
// classes are shown above
$allowed = [
'json' => 'JsonResponse',
'text' => 'SerialResponse'
];
$data = ['A' => 111, 'B' => 222, 'C' => 333];
echo (new $allowed[$_GET['type'] ?? 'json'])
->render($data);
本代码示例展示了在数组引用内使用任意表达式,并与 new
关键字结合使用的情况。
有关 PHP 8 中统一变量语法更新的更多信息,请参阅本文: https://wiki.php.net/rfc/variable_syntax_tweaks 。 |
现在让我们来看看 PHP 8 中字符串和数组处理的新技术。