Latest sites

  • 2017-11-26: New Drupal 8 site at Rue du Commerce, architected and tech-led by OSInet, just went throught Black Friday week with flying colors thanks to RabbitMQ
  • 2017-05-26: New headless Drupal 8 / Symfony 3 site at FranceTV Sport, architected and tech-led by OSInet, with RabbitMQ
  • 2017-02-20: New Drupal 8 site galaxy (+/- 70 sites) for Agences Régionales de Santé architected and tech-led by OSInet, delivered by Klee
  • 2015-08-21: 50% less server load with MongoDB on the Drupal 7 site factory at France Télévisions
  • 2015-07-15: Our first Drupal 8 production site at France Télévisions is live
  • 2014-08-18: 400% speedup in 3 weeks for http://france3-regions.francetvinfo.fr/ : who said Drupal back-offices had to be slow ?
  • 2014-02-07: Sotchi Olympics traffic not a problem for http://www.francetvsport.fr/ , which I rearchitected on Drupal 7 in 2013
  • 2011-09-14: Completed migration of FranceInfo.FR from SPIP to Drupal
  • 2011-07-13: The new social network features of Le Figaro are now powered by an OSInet-designed MongoDB implementation

Quick news

  • 2014-03-27: MongoDB Watchdog module ported to Drupal 8 at the Szeged Dev Days.
  • 2014-01-26: My post on the Symfony web profiler in Silex selected in Week of Symfony. w00t !
  • 2013-10-18: My first commit went into MongoDB today. And, guess what ? It's in JavaScript
  • 2013-09-20 to 29: Working on Drupal 8 EntityAPI at the extended code sprints during and around DrupalCon Prague
  • 2012-08-19: Working on Drupal 8 EntityAPI at Drupalcon Munich
  • 2012-06-15: Working on Drupal 8 EntityAPI at DrupalDevDays Barcelona
  • 2012-03-23: Working on the future Drupal Document Oriented Storage at DrupalCon Denver. D8 or later ? Bets are on Later

So you thought call_user_func() was just another way to call a PHP method...

In most cases, call_user_func() and call_user_func_array() are just slower but more flexible ways to call functions or methods. But it turns out they are not entirely equivalent where methods are involved. Consider this fragment, and guess the output.

<?php
/**
* This base class defines two methods of interest, one private, one protected.
*
* It also includes 3 ways to invoke these methods from outside.
*/
class Base {
 
/**
   * A private base method
   */
 
private function priv() {
    echo
__CLASS__ . " Private\n";
  }

 
/**
   * A protected base method
   */
 
protected function prot() {
    echo
__CLASS__ . " Protected\n";
  }

 
/**
   * Expose the private method
   */
 
public function callPriv() {
   
$this->priv();
  }

 
/**
   * Expose the protected method
   */
 
public function callProt() {
   
$this->prot();
  }

 
/**
   * Expose either method via call_user_func().
   */
 
public function call($method) {
   
call_user_func([$this, $method]);
  }

 
/**
   * Expose either method using Reflection.
   */
 
public function reflect($method) {
   
$rm = new ReflectionMethod($this, $method);
    if (!
$rm->isPublic()) {
     
$rm->setAccessible(true);
    }
   
$rm->invoke($this);
  }
}

/**
* Class Child redefines the methods of interest. Will overrides apply ?
*/
class Child extends Base {
 
/**
   * A child private method. Does it override the base method ?
   */
 
private function priv() {
    echo
__CLASS__ . " Private\n";
  }

 
/**
   * A child protected method. Does it override the base method ?
   */
 
protected function prot() {
    echo
__CLASS__ . " Protected\n";
  }
}

$f = new Child();

$f->callPriv();
$f->call('priv');
$f->reflect('priv');

echo
"\n";

$f->callProt();
$f->call('prot');
$f->reflect('prot');
?>

The question

So what will the output be ? Since $f is a Child instance, will it actually display "Child private" 3 times, then "Child protected" 3 times too ?

Answer on the Vulcan Logic dumper site: https://3v4l.org/Aoflo !

The results

VLD output for method callsAs you can see, the results are a bit unexpected, to say the least:

  • In all cases, invoking the protected method always invokes the child method.
  • However, the calls to the private method differ: $this->callPriv() invokes the base method, while $this->reflect('priv') invokes the child method
  • Even more interestingly, in HHVM, $this->call('priv') will diverge from PHP and invoke the base method while PHP invokes the child method

The explanation

Thanks to jbafford for this explanation on ##php.

What is actually happening is that private methods on the Base and Child classes are actualy isolated from each other, so when invoking $this->callPriv() on the instance, it is invoked in the Base context since that is where it lives, and at this point all it can see is the base method, not the child one.

To fix this, reimplement callPriv on the Child class, and it will see the child method, not the one on the parent class, as in https://3v4l.org/rriqc

And for extra insights (quoted with permission):

The _expected_ behavior would be for call_user_function to call the parent, which would make it consistent with $this->priv(), $this->$privInAVariable(), but then you'd never be able to have a child pass its private function as a callback to its parent. Where it's really bad is if you have three levels of nesting, and the middle level needs its function executed as a callback. To do that, you have to involve a closure.