skip to Main Content

I am a bit stuck with question why in PHP 7 dropped functionality of accesing object methods using array elements as method name.

E.g.:

$carObj = new Car();
$array  = ['method'=>'getMilage', 'object'=>$carObj];

// FATAL HERE:
$mileage = $array['object']->$array['method']();

// WORKS OK:
$objName = $array['object'];
$metName = $array['method'];
$mileage = $objName->$metName();

This code works on PHP 5.6 for sure, however when switched to PHP 7.1 it throws now fatal. Failed to find anything re this in release notes and SO topics.

P.S. Originally found this in Magento 1.14.2.0 version upon PHP upgrade, as Varien library uses this code:

File: Varien/File/Uploader.php

//run validate callbacks
foreach ($this->_validateCallbacks as $params) {
    if (is_object($params['object']) && method_exists($params['object'], $params['method'])) {
        $params['object']->$params['method']($this->_file['tmp_name']);
    }
}

Gives this:

Fatal error: Uncaught Error: Function name must be a string in
/var/www/html/lib/Varien/File/Uploader.php on line 274

EDIT #1:

You can TEST it here:

http://sandbox.onlinephpfunctions.com/code/d1d2d36f96a1b66ed7d740db328cd1f14cc2d7d8

3

Answers


  1. You must add $ before the object variable

    $carObj = new Car();
    $array  = ['method'=>'getMilage', 'object'=>'carObj'];
    
    $object = $array['object'];
    $method = $array['method'];
    // FATAL HERE:
    $mileage = $$object->$method();
    
    // WORKS OK:
    $objName = $array['object'];
    $metName = $array['method'];
    $mileage = $$objName->$metName();
    
    Login or Signup to reply.
  2. Your code works for sure not in PHP5.6

    The content of $array['object'] is an string and using the -> member operator on an string always throws an error

    Call to a member function getMilage() on string in […][…] on line […]

    The only way to get this to work is resolve the var with $ or – even better store the object inside the array and not simply the var.

    $mileage = ${$array['object']}->$array['method']();
    

    better solution

    $array  = ['method' => 'getMilage', 'object' => $carObj];
    $mileage = $array['object']->{$array['method']}();
    

    Sidenote: in php7 they changed the evaluation order in case of ambiguities – so you have to add explicitly {} around $array['method']. To prevent this, one would normaly extract first the object and method and then simply call it without the array dereferencing.

    Btw. the Magento Varien code you posted also expects $params['object'] to be an array. There is even a is_object test to ensure, you couldn’t pass just var names.

    //run validate callbacks - even in php7
    foreach ($this->_validateCallbacks as $params) {
        if (is_object($params['object']) && method_exists($params['object'], $params['method'])) {
            $object = $params['object'];
            $method = $params['method'];
            $object->$method($this->_file['tmp_name']);
        }
    }
    
    Login or Signup to reply.
  3. (Note: I’m assuming the 'object'=>'carObj' declaration is supposed to be 'object'=>$carObj here – there’s no way this code works in any version of PHP otherwise.)

    The clue is in the Notice: Array to string conversion in… notice raised before the fatal error.

    In PHP 5, the following statement:

    $array['object']->$array['method']();
    

    is evaluated like this:

    $array['object']->{$array['method']}();
    

    where $array['method'] is evaluated before calling it on the object.

    In PHP 7, it’s evaluated like this

    ($array['object']->$array)['method']();
    

    where the $array property is looked up on the object first. Since it doesn’t exist (obviously, since it’s an array), a notice is thrown, and then a subsequent fatal error when the method itself can’t be called.

    If you want to preserve the PHP 5 behaviour, wrap some {} around the method name lookup:

    $carObj = new Car();
    $array  = ['method'=>'getMilage', 'object'=>$carObj];
    
    $mileage = $array['object']->{$array['method']}();
    

    See https://3v4l.org/Is5lX

    This is explained in a bit more detail here: http://php.net/manual/en/migration70.incompatible.php

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search