Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP 8, function alias compatibility `getdir()`

While testing if my php script is php-8 compatible, I got stuck on the following code:

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

Prior to php-8, this worked fine, however, on php-8 it throws:

Fatal error: Cannot redeclare getDir()

3v4l.org


After searching for a while, I've found that php-8 introduced a new alias to dir():

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

php-src line 709

Questions

  • Can I get my code to work on php-8 without renaming the function?
  • Is there a list of all new function aliases?
    • dir() doesn't mention the alias
    • PHP 8 Release Announcement doesn't mention the alias either
like image 345
0stone0 Avatar asked Mar 29 '21 12:03

0stone0


Video Answer


2 Answers

Short answer: Whoopsie

Long answer: https://externals.io/message/113982

At the moment, I would plan on this being gone by 8.0.5 Sorry for the break, and thanks to Chris for filing a bug report abut this: https://bugs.php.net/bug.php?id=80914

like image 93
Sara Avatar answered Oct 20 '22 19:10

Sara


This turned out to be a lot more interesting than I expected.

The short answer is that getdir() really is new in PHP 8.0.0, but this was a mistake, and it will probably be removed in 8.0.4 or 8.0.5.

The interesting part is that getdir() is not in fact an alias, but the real name of the function internally; it's just that until 8.0, it was only accessible via its alias, dir(). To explain that, we have to go back more than 20 years...


The dir() function was added in PHP 3.0. For whatever reason - perhaps a last-minute change of name - the C function that implemented it was called "php3_getdir" not "php3_dir". That didn't matter, because every function name was mapped explicitly, like this:

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}
};

Not long after, PHP 4 came along, and function definitions moved to using macros to match the C name to the PHP name. Since the name of the function and implementation didn't match, "dir" ended up labelled as an "alias"; but no extra entry was added for "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}
};

An alias without a target doesn't really make sense (and there was a PHP_NAMED_FE macro for just this purpose) but it worked, so I guess nobody noticed.

In fact, through all the changes of PHP 5 and PHP 7, it carried on working, with basically the same line of C code right up to 7.4.

PHP_FALIAS(dir,  getdir, arginfo_dir)

During the work on PHP 8, however, a system was built to generate internal function information from PHP "stubs". As part of this stubs were added for all function aliases, and getdir() ended up with 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 {}

This was then used to re-generate the C definitions, and finally getdir() had its own function entry

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

This caused getdir() to be a real built-in function name, and meant you couldn't have a function with the same name.


From there, four things have happened:

  • 29th March 2021: 0stone0 posted this question.
  • Chris Haas tried to hunt down the issue, and opened a bug on the PHP bug tracker, thinking that the issue related to case sensitivity. They also confirmed that getdir() was the only alias in basic_functions.stub.php not in the manual.
  • 6th April 2021: Thinking I was going to make a quick documentation fix, I got interested, and disappeared down the above rabbit hole. I posted my findings to the PHP internals mailing list and went to bed an hour later than I intended.
  • Sara Golemon (one of the PHP 8.0 Release Managers) replied agreeing that it should be treated as a bug and reverted in the next 8.0.x release. She also posted an answer here since I hadn't yet.
like image 36
IMSoP Avatar answered Oct 20 '22 20:10

IMSoP