PHP 8,函数别名兼容性`getdir()`

Posted

技术标签:

【中文标题】PHP 8,函数别名兼容性`getdir()`【英文标题】:PHP 8, function alias compatibility `getdir()` 【发布时间】:2021-06-25 12:12:28 【问题描述】:

在测试我的 php 脚本是否与 php-8 兼容时,我被以下代码卡住了:

function getDir($a, $o = 2) 
    $d = Floor($a / $o);
    return ($d % 2 === 0);

在php-8 之前,这工作正常,但是,在php-8 它抛出:

致命错误:无法重新声明 getDir()

3v4l.org


搜索了一会,发现php-8给dir()引入了一个新别名:

/** @param resource $context */
function getdir(string $directory, $context = null): Directory|false 

php-src line 709

问题

我能否让我的代码在php-8 上运行而不重命名函数? 是否有所有新函数别名的列表? dir() 没有提到别名 PHP 8 Release Announcement 也没有提及别名

【问题讨论】:

getdir 别名似乎很老了(github.com/php/php-src/blob/php-4.4.9/ext/standard/…。我在 php 迁移指南中没有看到任何关于函数重新声明的通知,这可能是 PHP 8 修复的错误 @ADyson 好吧,做了什么:3v4l.org/Zgork Can I get my code to work on php-8 without renaming the function...除非你改变它的范围(例如,把它放在一个类中,也许)。 我将此提交给PHP bug database。尽管我同意将用户级函数命名为与内置函数相同是自找麻烦,但不应期望对未记录的(据我所知)别名执行相同操作。我认为核心支持的所有函数别名至少应该在文档中列出,即使在“函数别名请不要使用页面”上也是如此。如果测试功能可以将其报告为别名,那将是一个奖励,但我认为引擎此时无法区分。 情节变厚了:这不是区分大小写的问题,函数真的不存在:3v4l.org/dCpeh 但它一直在源代码中。这里发生了非常奇怪的事情。 【参考方案1】:

简答:哎呀

长答案:https://externals.io/message/113982

目前,我计划在 8.0.5 之前解决此问题

【讨论】:

【参考方案2】:

事实证明这比我预期的要有趣得多。

简短的回答是 getdir() 在 PHP 8.0.0 中确实是新的,但这是一个错误,它可能会在 8.0.4 或 8.0.5 中被删除。

有趣的是 getdir() 实际上并不是一个别名,而是函数内部的真实名称;只是在 8.0 之前,它只能通过其别名 dir() 访问。要解释这一点,我们必须回到 20 多年前……


dir() 函数是在 PHP 3.0 中添加的。无论出于何种原因——也许是在最后一刻更改名称——实现它的 C 函数被称为“php3_getdir”而不是“php3_dir”。没关系,因为每个函数名称都被显式映射,如下所示:

function_entry php3_dir_functions[] = 
    "opendir",     php3_opendir,   NULL,
    "closedir",    php3_closedir,  NULL,
    "chdir",       php3_chdir,     NULL,
    "rewinddir",   php3_rewinddir, NULL,
    "readdir",     php3_readdir,   NULL,
    "dir",         php3_getdir,    NULL,
    NULL, NULL, NULL
;

不久之后,PHP 4 出现了,函数定义moved to using macros 将 C 名称与 PHP 名称相匹配。由于函数和实现的名称不匹配,“dir”最终被标记为“别名”;但没有为“getdir”添加额外的条目:

static zend_function_entry php_dir_functions[] = 
    PHP_FE(opendir,     NULL)
    PHP_FE(closedir,    NULL)
    PHP_FE(chdir,       NULL)
    PHP_FE(rewinddir,   NULL)
    PHP_FE(readdir,     NULL)
    PHP_FALIAS(dir,     getdir, NULL)
    NULL, NULL, NULL
;

没有目标的别名实际上没有意义(并且有一个 PHP_NAMED_FE 宏仅用于此目的)但它有效,所以我想没有人注意到。

事实上,通过 PHP 5 和 PHP 7 的所有更改,它继续工作,with basically the same line of C code right up to 7.4。

PHP_FALIAS(dir,  getdir, arginfo_dir)

然而,在 PHP 8 的工作期间,构建了一个系统来从 PHP“存根”生成内部函数信息。作为 stubs were added for all function aliases 的一部分,getdir() 以 its own stub 结束:

/** @param resource $context */
function getdir(string $directory, $context = null): Directory|false 

/**
 * @param resource|null $context
 * @alias getdir
 */
function dir(string $directory, $context = null): Directory|false 

然后用它来重新生成 C 定义,最后是getdir() had its own function entry

ZEND_FE(getdir, arginfo_getdir)
ZEND_FALIAS(dir, getdir, arginfo_dir)

这导致 getdir() 成为真正的内置函数名,这意味着您不能拥有同名的函数。


从那里开始,发生了四件事:

2021 年 3 月 29 日:0stone0 发布了这个问题。 Chris Haas 试图追查问题,并打开a bug on the PHP bug tracker,认为问题与区分大小写有关。他们还确认 getdir() 是 basic_functions.stub.php 中唯一不在手册中的别名。 2021 年 4 月 6 日:我想我要快速修复文档,我产生了兴趣,然后消失在上面的兔子洞里。我posted my findings to the PHP internals mailing list 比我预想的晚了一个小时睡觉。 Sara Golemon(PHP 8.0 发布经理之一)回复同意应将其视为错误并在下一个 8.0.x 版本中恢复。她还posted an answer here,因为我还没有。

【讨论】:

以上是关于PHP 8,函数别名兼容性`getdir()`的主要内容,如果未能解决你的问题,请参考以下文章

为 PHP5.2- 框架提供 PHP5.3+ 命名空间的类名别名

为啥 PHP 允许“不兼容”的构造函数?

PHP json_encode()函数兼容PHP 4

为日期/时间函数设置默认时区(PHP5.3兼容性要求)

Drupal 7与PHP 7的兼容性

2017年8月20日第四篇