Please consider replacing function_exists() with is_callable() in at least menu.inc and form.inc so that object/class methods can be registered as callbacks for forms and menus.

I am currently patching menu.inc and form.inc to allow them to be used in this way, but I'd like to see the functionality in core.

I have not tested Drupal 6.

CommentFileSizeAuthor
#1 patch.patch4.37 KBstashlbai

Comments

stashlbai’s picture

Component: base system » forms system
Status: Active » Needs review
StatusFileSize
new4.37 KB

The attached code add functionality to $form['#validate'] and $form['#submit'] in a backward-compatible fashion. In particular: if you want to use PHP5 callback style function declarations, then you must add a validate or submit function thus:

$element['#validate'][] = array ( 'callback' => array('class or obj', 'method'), 'callback arguments' => array());

This is modeled on the menu callback definition paradigm.

scoutbaker’s picture

Version: 5.7 » 7.x-dev

Feature requests need to go against the current development version in Drupal 7.

Crell’s picture

Under what circumstances would we want to use a method or static method for a menu or form callback? If we do, shouldn't that be integrated into the menu/form structure more cleanly?

Arto’s picture

+1 for this change - I recall having to write a silly wrapper function in a similar situation before.

stashlbai’s picture

A dispatcher/controller can be implemented as a class with static methods, or as a dispatcher object. In both cases the controller's state can be encapsulated in class or instance variables. This can be useful for various reasons. For example, see the content_copy module, which stores away state in $GLOBALS[] while it's processing a type for export. It has to because the data is being generated/saved via multiple calls to drupal_execute, which make it impossible to store state, for example, in a single form.

stashlbai’s picture

It does not seem like it would be hard to apply this idea to D6/D7; it would require being careful about serializing/unserializing the callback definitions to menu_router, etc. I did not review the effort required for the forms system. I realize this is much less helpful than an actual patch, but we're unable to commit the time to that since we're staying with D5 for now.

Crell’s picture

A form submit handler can have a static variable quite easily, and store data in its own static non-global object. To wit:

class MyClass {
  protected $persistentStuff;
  function process($form_id, $form_state) {
    // Do stuff
  }
}

function example_form_submit($form_id, $form_state) {
  static $data;

  if (empty($data)) {
    $data = new MyClass();
  }

  return $data->process($form_id, $form_state);
}

Factory functions are *really* easy in PHP. I'm still not convinced of the need here. Besides, the Registry patch will be changing the way that works anyway. :-)

stashlbai’s picture

I think what's more to the point is that the form and menu handlers currently expect callback functions (validate, submit, load, access, etc.) to be in the global function namespace.

Adding support for calling class/instance methods doesn't preclude this assumption, nor does it interfere; and I think it would also be reasonable for users to expect these callback handlers to support namespaces once PHP 5.3 becomes widely adopted. Using is_callable() instead of function_exists() for checking, and registering/serializing callback structures (instead of or in addition to raw function names) doesn't break the existing assumption (callbacks registered in global function namespace), and allows the use of advanced PHP features without requiring the 'pollution' the global function namespace.

If the issue is that this proposal would require work to implement: fair enough. The onus should be on the submitter to either write or sponsor the code.

But I don't see any philosophical arguments in opposition which to me hold any water.

Crell’s picture

@stashlbai: The question for me that has still not been answered is "er, why?" Any patch or feature request needs to be able to answer that question, which is sometimes easy and sometimes difficult. In this case, I still don't understand "er, why?" (And I say that as a strong proponent of leveraging more OOP in Drupal 7 where it makes sense to do so; I'm just not convinced that this "makes sense to do so".)

As for namespaces in PHP 5.3, that's not on our radar for a while yet. :-) Besides, the current implementation is rather function-unfriendly, IMO. Static methods and namespaced functions look identical, and the response on php-internals when that was raised was "who the heck uses both classes and functions and would need namespaces?" Of course, I do, but they don't listen to me. :-)

maartenvg’s picture

Status: Needs review » Needs work

Patch no longer applies.

effulgentsia’s picture

Version: 7.x-dev » 8.x-dev

D8 material, where hopefully, we'll usher in much more OOP support where it makes sense to do so.

chx’s picture

Category: feature » task
Priority: Normal » Critical

Bump! We are now on PHP 5.3 and this is a must. instead of writing one-liner process - ajax wrapper - whatnot functions and putting their names in we could put in the function itself. WIN.

webchick’s picture

Priority: Critical » Major

Not critical. Nothing breaks horribly if this isn't done, as evidenced by Drupals 1, 2, 3...

catch’s picture

Note that there are several patches in the queue that remove function_exists() checks where they cause things to silently fail.

#1059884: Drop function_exists for 'callback' functions is one. Let's try to consider that as well as/instead of writing a huge find and replace patch. This isn't an argument against using is_callable() at all.

quicksketch’s picture

Priority: Major » Normal
Status: Needs work » Postponed (maintainer needs more info)

The existing patch is for Drupal 5, clearly not even close to usable at this point. Repeating Crell in #9, this issue is not adequately explained. If there is a demonstrable benefit or reason, this can be bumped. As is, our new policy at http://drupal.org/node/1201874 causes issues like this one to prevent new feature development if it's categorized as major.

quicksketch’s picture

Status: Postponed (maintainer needs more info) » Closed (won't fix)

Closing after lack of activity.