Store but not EXECUTE a Global Function (PHP)

Tags: , , ,



This is an odd situation and I think the answer is ‘you can’t do that, what are you thinking?’ but hope someone can prove me wrong.

My goal is to store a globally scoped function in a variable then inject it for execution within a class object.

  • I would like to avoid using call_user_func() as this searches for the function in the global namespace and is the same effect as if I were to just execute the global function from within the class object. I would like my class to execute the object as if it were an internal class method, not an external function. This comes close but not quite.
  • I cannot modify the function or wrap it in a class.
  • (Why am I jumping through these hoops?) Needs to be used within this class to follow a spec.

I know I can just duplicate the function in the class and be done with it, but you know the issues with that (plus it creeps up on SRP.) Reflection would work perfectly but this function is not in a class, it is just out there in an include. I’ve tried wrapping it an anonymous function and the closure object doesn’t execute the function.

Is there any hope to do this? The function is simple, accepts a scalar param, does some stuff to it, returns a value (and is tightly coupled with other code, cannot be moved or changed.)

function someFunction($param)
{
  // do some stuff
  return $someScalarValue;
}

What I would hope is something like

$func = someFunction([some value]); // doesn't work of course, this would store result in $func
$cls = new SomeClass($func);

Then a method in the class could run the function object, much like call_user_func but not have to search the global namespace.

protected function someThing()
{
  $this->injected_function([some class value]); // also doesn't work of course
}

Answer

Thank you @Markkus Zeller for your comments, as I suspected there is no way to do what I originally was tasked, to “inject” a global function as an dependency. There is, but it only really works with anonymous functions.

After a lot of stressful pushback, I convinced our managers that wrapping this in a simple class was the way to go. This,

// require_once('some-function.php');

function someFunction($param)
{
  // do some stuff
  return $someScalarValue;
}

. . . now becomes this. (Typed out on the fly and may contain deficiencies, concept only)

// require_once('some-function.php');

require_once('path/to/SomeFunctionClass.php');
function someFunction($param)
{
  $cls = new SomeFunctionClass($param);
  return $cls->execute();
}

. . . where execute() contains identical code that was in someFunction(). I can now use “SomeFunctionClass” for a DI. There is more to the story, but that is the gist, and this one change can be implemented without modifying any of the 450 or so instances that use this global function (and each of those they can be gradually ported to use the new wrapper.) It also allows me to isolate and mock the functionality for unit testing.



Source: stackoverflow