Indirect Invocation Considered Harmful

There is a bug in PHP that prevents scalar type declarations to be interpreted strictly when a function or method is invoked using the Reflection API.

Consider a class C that has a method m which expects a parameter $x of type string:

1 2 3 4 5 6 7 8
< ? php
class C
{
public function m ( string $x )
{
var_dump ( $x ) ;
}
}

Let us try to pass an integer instead of a string, which, when we enable strict interpretation of scalar type declarations, should yield a type error.

When we invoke that method directly, we get the error we expect:

1 2 3 4 5
< ? php
declare ( strict_types = 1 ) ;

$o = new C ;
$o -> m ( 1 ) ;

Executing the code shown above will print the output shown below:

Fatal error: Uncaught TypeError: Argument 1 passed to C::m()
must be of the type string, integer given, called in ...

If we, however, invoke the method indirectly then PHP will not generate the expected type error.

1 2 3 4 5 6 7 8
< ? php
declare ( strict_types = 1 ) ;

$object = new C ;
$arguments = [ 1 ] ;

$method = new ReflectionMethod ( $object , 'm' ) ;
$method -> invokeArgs ( $object , $arguments ) ;

Instead, executing the code shown above will print the output shown below:

string(1) "1"

While the discussion of that bug mentions that other forms of indirect invocation might also be affected, we were only able to reproduce the bug for the Reflection API. We tried callbacks with functions such as array_map(), the call_user_func() function, and the $object->$method() syntax. For all these forms of indirect invocation a type error was raised, as is expected and correct.

In the example above, the Reflection API is used to invoke a method with arguments coming from an array. The same effect can be achieved using argument unpacking:

1 2 3 4 5 6 7
< ? php
declare ( strict_types = 1 ) ;

$object = new C ;
$arguments = [ 1 ] ;

$object -> m ( ... $arguments ) ;

Executing the code shown above will once again print:

Fatal error: Uncaught TypeError: Argument 1 passed to C::m()
must be of the type string, integer given, called in ...

We hope that developers do not use this bug in PHP to bypass type safety in code that they call – and, of course, that this bug will be fixed soon.


This article is an excerpt from our eBook PHP 7 Explained, which we have updated for PHP 7.2 recently.

For more insights into PHP 7, get your copy now, it includes life-long free updates.

Über die Autoren

Sebastian Bergmann
Sebastian Bergmann
Twitter LinkedIn Xing

Sebastian Bergmann ist ein international gefragter Experte, der als Schöpfer von PHPUnit wesentlich zur Professionalisierung der PHP-Community beigetragen hat.

Arne Blankerts
Arne Blankerts
Twitter LinkedIn Xing

Arne Blankerts schuf schon vor Jahren IT-Lösungen, die ihrer Zeit weit voraus waren. Er spürt Sicherheitslücken mit fast magischer Intuition auf.

Stefan Priebsch
Stefan Priebsch
Twitter LinkedIn Xing

Stefan Priebsch findet seit über 20 Jahren mit einer einzigartigen Mischung aus neuen Ideen und erprobten Ansätzen für jedes Problem eine zukunftsfähige Lösung.

Artikel teilen
Why PHP 7.2 Is Important The Future of Zend