Bug #23241 See Comments

Hook channel_form_entry_form_tagdata_start does not allow passing by reference anymore

Version: 3.5.11 Reporter: Matt Johnson

I am converting an add-on from it’s EE2 version to EE3, and it uses the channel_form_entry_form_tagdata_start hook. It appears that the ability to pass the $channel_form_object variable as reference has been removed. I’m getting this error when attempting to get the variable as a reference variable:

CHANNEL_FORM_ENTRY_FORM_TAGDATA_START() EXPECTED TO BE A REFERENCE, VALUE GIVEN

I followed the error, and found the hook in ee/EllisLab/Addons/channel/libraries/channel_form/Channel_form_lib.php where it says in a comment:

// -------------------------------------------
// 'channel_form_entry_form_tagdata_start' hook.
//  - Developers, if you want to modify the $this object remember
// to use a reference on func call.
// -------------------------------------------

I followed the code, and in ee/legacy/libraries/Extensions.php on line 245, it is calling the hook like this: call_user_func_array(array($obj, $method), $args) where $args needs to be an array of reference variables in order to work.

When I looked into the function in older versions of EE, I found that it used to do exactly this. It looped through the array, and made sure each variable was passed as reference, so a add-on developer could modify it. When I modified the $args variable, it worked as intended again:

foreach ($args as $k => $v)
{
    $args[$k] =& $args[$k];
}

I should also note that I have tested in the most recent versions of PHP 5.6, 7.0 and 7.1 with varying results. If I leave the core untouched, and request the variables as value instead of reference, I am getting mixed results. In PHP 5.6 and 7.0, this does exactly what I would expect: changing the object does not alter the actual channel form data at all. However, when testing in PHP 7.1, I noticed that I could receive the variables as value, not reference, and I could still alter them as reference variables. Either way, adding the foreach loop and requesting the variables as reference fixed the problem in every PHP version.

  • That code comment looks like it needs to be updated, severely! PHP changed how objects are passed and assigned by default all the way back in PHP 5, so you do not need to pass them by reference anymore.

    call_user_function_array() doesn’t always do what you expect though, so I double checked that hook in PHP 5.6, 7.0, and 7.1, and was able to modify the object fine. My test was simple:

    public function cf_entry_form_tagdata_receiver($tagdata, $obj)
     {
      $obj->form_error = 'Change this public boolean property to a silly string';
      return $tagdata;
     }

    Then back in the Channel_form_lib class, after the hook I var_dump($this); and see that my modified property stuck. I don’t want to completely rule out a bug, so if you can post a reproducible reduction test of what you’re doing, and describing what’s not working, I’m happy to look further.

    Derek Jones
    29th September, 2017 at 2:15pm
  • Hi Derek,

    Thanks for looking into this. It looks like I was getting that error because I passed by reference, which was a fatal error, since the function wasn’t explicitly sending them as reference variables.

    Adding my fix removed that error, and let the page render. The weird thing is that the data I was comparing was coming through a different hook, which also was trying to pass by reference. I never noticed it though, because it was silently failing on form submission, but going to the next page anyways as if it worked fine.

    When I added that pass by reference snippet of code to the core, it fixed both cases of passing by reference, so everything worked. When I took out the & on all of my relevant hooks, it all worked again.

    Again, thanks for looking at this!

    Matt Johnson
    05th October, 2017 at 3:50pm
  • No problem, thanks for the follow up!

    Derek Jones
    05th October, 2017 at 6:19pm

You must be signed in to comment on a bug report.

ExpressionEngine News

#eecms, #events, #releases