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

17

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

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

之前,这个是正常工作的,但是在 中会抛出如下错误:

Fatal error: Cannot redeclare getDir()

3v4l.org


搜索了一段时间后,我发现dir() 引入了一个新的别名:

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

php-src 第 709 行

问题

  • 我能否在不更改函数名称的情况下使我的代码在 上工作?
  • 是否有所有新函数别名的列表?

2
getdir 别名似乎非常古老(< PHP 5)https://github.com/php/php-src/blob/php-4.4.9/ext/standard/basic_functions.c#L714。我在 php 迁移指南中没有看到任何关于函数重新声明的通知,也许这是一个在 PHP 8 中修复的 bug。 - thehennyy
3
@ADyson 嗯,确实有东西: https://3v4l.org/Zgork - deceze
2
我能让我的代码在php-8上运行而不重命名函数吗?除非你改变它的作用域(例如,将其放在一个类中),否则不行。 - ADyson
3
情节变得扑朔迷离:这不是大小写敏感的问题,这个函数真的不存在:https://3v4l.org/dCpeh 但是它一直存在于源代码中。这里发生了非常奇怪的事情。 - IMSoP
2
我本来以为我测试过 function_exists('getdir'),但可能只是在 PHP 8 的本地环境中测试过。感谢 @IMSoP 进一步调查此事。 - Chris Haas
显示剩余7条评论
2个回答

14

11
这事情比我预料的有趣多了。
简短回答是getdir()确实是PHP 8.0.0版才新增的,但这是个错误,很可能在8.0.4或8.0.5版中被移除。有趣的是,getdir()事实上并不是一个别名,而是函数内部的真实名称;只不过在PHP 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推出了,函数定义转移到使用宏来匹配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 的所有更改中,它都继续工作,并且在 7.4 版本中基本上使用相同的 C 代码行

PHP_FALIAS(dir,  getdir, arginfo_dir)

在开发PHP 8期间,建立了一个系统,从PHP“存根”生成内部函数信息。作为其中的一部分,为所有函数别名添加了存根,getdir()最终拥有了自己的存根
/** @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()具有自己的函数入口

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

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


从那时起,发生了以下四件事:

  • 2021年3月29日:0stone0发布了这个问题。
  • Chris Haas试图查找问题,并在PHP错误跟踪器上打开了一份错误报告,认为该问题与大小写敏感性有关。他们还确认getdir()是basic_functions.stub.php中唯一不在手册中的别名。
  • 2021年4月6日:我认为我将快速修复文档,但却对以上内容产生兴趣,并深入研究。我在PHP内部邮件列表上发布了我的发现,并比预期晚了一个小时去睡觉。
  • Sara Golemon(PHP 8.0版本发布管理员之一)回复同意应将其视为Bug并在下一个8.0.x版中撤销。由于我没有回复,她还在这里发布了答案

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接