Skip to content

Error when mocking built-in function with pass-by-reference argument and argument with default value (PHP 8) #201

@jimbonator

Description

@jimbonator

This is for AspectMock 4.1.1.

During our migration from PHP 7.4 to PHP 8.1, we've encountered this pattern a few times:

When our PHP-Unit tests mock a PHP built-in function that has at least one argument passed by reference and one argument with a default value, the mock fails with the error ParseError: syntax error, unexpected token "=", expecting ")".

The stack track looks like this:

/tmp/flockoipmSG:4
/petabox/www/common/vendor/codeception/aspect-mock/src/AspectMock/Core/Mocker.php:275
/petabox/www/common/vendor/codeception/aspect-mock/src/AspectMock/Core/Registry.php:38
/petabox/www/common/vendor/codeception/aspect-mock/src/AspectMock/Test.php:248

Examining the temporary file reveals the problem:

$ cat /tmp/flockoipmSG
<?php
namespace Atomic;
if (!function_exists('Atomic\flock')) {
    function flock($p0, int $p1, &$p2 = null=NULL) {
         $args = [];
         switch(count(func_get_args())) {
             case 3: $args = [$p0, $p1, &$p2]; break;
             case 2: $args = [$p0, $p1]; break;
             case 1: $args = [$p0]; break;
         }
         if (($__am_res = __amock_before_func('Atomic','flock', $args)) !== __AM_CONTINUE__) {
             return $__am_res;
         }
         return call_user_func_array('flock', $args);
    }
}

The function declaration has two default values for an argument (function flock($p0, int $p1, &$p2 = null=NULL).

Other functions which have given us this problem are:

  • system()
  • stream_socket_client()
  • stream_select()

The last one is interesting because, unlike the others, the passed-by-reference arguments don't have default values. Only the final argument does:

stream_select(
    ?array &$read,
    ?array &$write,
    ?array &$except,
    ?int $seconds,
    ?int $microseconds = null
): int|false

That's what leads me to believe the problem is the existence of both in the function signature, but not necessarily that a single argument needs to be both pass-by-reference and have a default value for this to fail.

We don't see this under PHP 7.4, so I assume this related to the PHP version.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions