Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does passing a variable by reference not work when invoking a reflective method?

My function, prepare(), has the definition:

private function prepare(&$data, $conditions=null, $conditionsRequired=false)

When I test it, this

  /**
  * @covers /data/DB_Service::prepare
  * @uses /inc/config
  */
  public function testNoExceptionIsRaisedForValidPrepareWithConditionsAndConditionsRequiredArguments() {
    $method = new ReflectionMethod('DB_Service', 'prepare');
    $method->setAccessible(TRUE);

    $dbs = new DB_Service(new Config(), array('admin', 'etl'));
    $data = array('message' => '', 'sql' => array('full_query' => ""));
    $method->invoke($dbs, $data, array('conditionKey' => 'conditionValue'), TRUE);
  }

raises (and breaks my test)

ReflectionException: Invocation of method DB_Service::prepare() failed

However, this

  /**
  * @covers /data/DB_Service::prepare
  * @uses /inc/config
  */
  public function testNoExceptionIsRaisedForValidPrepareWithConditionsAndConditionsRequiredArguments() {
    $method = new ReflectionMethod('DB_Service', 'prepare');
    $method->setAccessible(TRUE);

    $dbs = new DB_Service(new Config(), array('admin', 'etl'));
    //$data is no longer declared - the array is directly in the call below
    $method->invoke($dbs, array('message' => '', 'sql' => array('full_query' => "")), array('conditionKey' => 'conditionValue'), TRUE);
  }

works perfectly and the test is successful.

Why does declaring the variable and then passing not work, but simply creating it in the method call does work? I think this has something to do with how invoke() works, but I can't seem to figure out what.

like image 678
Matthew Herbst Avatar asked Oct 01 '14 03:10

Matthew Herbst


1 Answers

From the documentation for invoke:

Note: If the function has arguments that need to be references, then they must be references in the passed argument list.

So, your first example should work if you change it to:

$method->invoke($dbs, &$data, array('conditionKey' => 'conditionValue'), TRUE);

EDIT: To avoid deprecated call time pass-by-reference, you can use an array and invokeArgs:

$method->invokeArgs($dbs, array(&$data, array('conditionKey' => 'conditionValue'), TRUE));
like image 51
wavemode Avatar answered Sep 18 '22 17:09

wavemode