Variable Reference as Function Argument - php

All about a Zend Application with an action helper.
I want to unset some pairs of an array by a function.
helper:
class Application_Controller_Action_Helper_TestHelper extends Zend_Contr[...]
{
public function direct(&$array)
{
if(isset($array['key']))
unset($array['key']);
}
}
controller:
$this->_helper->TestHelper($var);
How could I get it working?

Since you are now passing by reference, you can modify the variable in the method and the changes will be applied to the original variable. However, the way you have it now you are not changing the variable at all, just returning the result of the expression, like in your first example. You should have something like this instead:
class Application_Controller_Action_Helper_TestHelper extends Zend_Contr[...] {
public function direct(&$var) {
$var = $var + 1;
}
}

You must also pass it as reference:
$this->_helper->TestHelper(&$var);
UPDATE:
Ups, I had my errors turned off. You (and now me) are getting the error because...
There is no reference sign on a function call - only on function
definitions. Function definitions alone are enough to correctly pass
the argument by reference. As of PHP 5.3.0, you will get a warning
saying that "call-time pass-by-reference" is deprecated when you use &
in foo(&$a);.
ZF's HelperBroker uses return call_user_func_array(array($helper, 'direct'), $args); to call your direct() method. Check the docs, but it seems call_user_func_array passes by reference, although with several quirks.
Check out this answer.

Related

PHP - is there a way to save an already defind function in a variable?

I am interested in something google couldn't really help me with...
I know that its possible to use anonymous functions and also store functions in a variable in PHP like that
$function = function myFoo() { echo "bar"; }
and call it using the variable: $function();
So far so good but what if I have a function or method declared somewhere but not saved on intializing?
I have a function that shall expect a callable, of course call_user_func() can help me here but then I need to pass the method name in my callback handler which I think is pretty unsafe because in the moment I add the callback I cant say if it really is a function and exists when I store it.
Thatswhy I would like to realize the following szenario:
This function:
function anyFunction() {
echo "doWhatever...!";
}
should be saved in a variable at a later point in time:
$myOtherFunction = get_registered_func("anyFunction");
I know get_registered_func() doesnt exist but I want to know if this is possible somehow!
With this I could now have another function
function setCallback(callable $theCallbackFunction) { }
And use it like this:
setCallback($myOtherFunction);
This would have a great advantage that an exception / a fatal is thrown when the parameter is no function or does not exist.
So in short, is there a way to store a previously defined, already existing function or method in a variable?
PHP's callable meta type can be:
a string
an array
an anonymous function
Only the latter one is somewhat "type safe", i.e. if you get an anonymous function you know it's something you can call. The other two options are merely formalised informal standards (if that makes sense) which are supported by a few functions that accept callbacks; they're not actually a type in PHP's type system. Therefore there's basically no guarantee you can make about them.
You can only work around this by checking whether the callable you got is, well, callable using is_callable before you execute them. You could wrap this into your own class, for example, to actually create a real callable type.
I see no reason why this shouldn't be possible, other than there not being a PHP function to do it. The anonymous function syntax is newly introduced in PHP, I wouldn'be surprised if it was still a little rough around the edges.
You can always wrap it:
function wrap_function ($callback) {
if (is_callable($callback) === false) {
throw new Exception("nope");
}
return function () {
call_user_func($callback, func_get_args());
}
}
$foo = new Foo();
$ref = wrap_function(array($foo, "bar"));
Not a good way, but maybe this helps you:
function foo($a) {
echo $a;
}
$callFoo = 'foo';
$callFoo('Hello World!'); // prints Hello

Call a non-global variable from a function?

During the development of a Joomla! plugin, I ran across something really interesting. One of the events does not have a return value, but it calls variables from inside the function. Prior knowledge tells me this should only work if the variables are global inside the function, yet the dispatcher is able to call the variables from outside the function.
EDIT: I just discovered that the variable that is accessed from inside the function needs to be one of the paramaters! Could this be func_get_params() or call_user_func()?
Calling Code:
$instance = JDispatcher::getInstance();
$instance->trigger(onJoomCalledEvent, array(&$link, $other_params));
Plugin (snippet):
class plgMyPlugin extends JPlugin{
onJoomCalledEvent($link, $other_params){
$link = "Some Value Here";
return false;
}
}
This function returns false, yet somehow the application (Joomla!) is able to extract the value of $link. How is this done?
Does the plug-in definition look like this:
class plgMyPlugin extends JPlugin{
onJoomCalledEvent(&$link, $other_params){
$link = "Some Value Here";
return false;
}
}
Than it's pass by reference. If it's indeed the way you posted above than it's call time pass by reference which is deprecated and emits a warning starting with PHP 5.3.

PHP Initialize class with a var is ok but with a constant it fail. Why?

I am currently building a MVC and I ran into a little problem (I got the solution already), but :
This fail because Fatal error: Call to undefined method Controller_Home::DMVC_DEF_CTRL_FUNCTION() ..
if(method_exists($Controller, DMVC_DEF_CTRL_FUNCTION)){
$Controller->DMVC_DEF_CTRL_FUNCTION($SecondRoute);
} else {
// 404
die;
}
This work :
$MethodName = DMVC_DEF_CTRL_FUNCTION;
if(method_exists($Controller, $MethodName)){
$Controller->$MethodName($SecondRoute);
} else {
// 404
die;
}
DMVC_DEF_CTRL_FUNCTION is a constant.
Can someone explain this to me why a constant wouldn't work ? I also tryed for fun with the constant function but no success.
I think PHP think it is a function. How can I tell PHP that the constant DMVC_DEF_CTRL_FUNCTION ain't a function ?
Thanks
If you want to use a constants value as method name, you could utilize the curly expression syntax:
$Controller->{CONSTANT_NAME}($SecondRoute);
As otherwise the identifier would only ever be interpreted as method name.
In your current code the interpreter believes that you are calling a method on the object with the name DMVC_DEF_CTRL_FUNCTION. Since DMVC_DEF_CTRL_FUNCTION is a constant and not a varaible, php is taking the name instead of the actual value it is holding.
You can force php to take the value instead in the following way:
$controller->{DMVC_DEF_CTRL_FUNCTION}( "Blah" );
Update
When using a class constant instead of a global constants, the following will work as well:
$controller->{self::DMVC_DEF_CTRL_FUNCTION}( "Blah" );
PHP knows that a variable holds data, that's the purpose of a variable. This is why you can use variable variables and execute a function like you're trying to do, by evaluating the variable How would it know that you meant to use this as a constant instead of just the actual name of the function?
You could use the following to execute the same purpose:
if(method_exists($Controller, DMVC_DEF_CTRL_FUNCTION)){
call_user_func(array($Controller, DMVC_DEF_CTRL_FUNCTION),$SecondRoute);
} else {
// 404
die;
}
For this line:
if(method_exists($Controller, DMVC_DEF_CTRL_FUNCTION)){
have you done a define('DMVC_DEF_CTRL_FUNCTION', 'some value') previously? If not, you're checking for an undefined constant, which will effectly become
if (method_exists($Controller, NULL)){
method_exists() requires you pass in the name of the method as a STRING. Since you've not quoted the DMVC... part, it's going in as a constant, which means it must have been defined previously.
edit:
$x = 'hello';
define('x', 'goodbye');
$obj->x(); // this is NOT going to call hello() **OR** goodbye()
PHP doesn't know that you aren't calling a function DMVC_DEF_CTRL_FUNCTION as in
function DMVC_DEF_CTRL_FUNCTION()
{
// some function
}
Crashspeeder is right. You can use call_user_func, but why not just tell PHP to replace the constant before it tries to call the function:
$Controller->{DMVC_DEF_CTRL_FUNCTION}($SecondRoute);
Add brackets around the constant.

PHP create_function Instance variable - Unable to call anonymous function: Follow up

This is somewhat a follow up to a previous question - but I've distilled the question down and have the "works" vs. "doesn't work" cases narrowed down much more precisely.
My Goal:
I have a class MyClass that has an instance variable myFunction. Upon creating a MyClass object (instantiating), the constructor assigns the instance variable myFunction with the result of a call to create_function (where the code and args come from a db call).
Once this object of type MyClass is created (and stored as an instance variable of another class elsewhere) I want to be able to call myFunction (the instance variable anonymous function) from "anywhere" that I have the MyClass object.
Experimental Cases -- below is my highly simplified test code to illustrate what works vs. what doesn't (i.e. when the expected functionality breaks)
class MyClass extends AnotherClass {
public $myFunction;
function __construct() {
$functionCode = 'echo "NyanNyanNyan";';
$this->myFunction();
/*Now the following code works as expected if put in here for testing*/
$anonFunc = $this->myFunction;
$anonFunc(); //This call works just fine (echos to page)!
/*And if i make this call, it works too! */
self::TestCallAnon();
}
public function TestCallAnon() {
$anonFunc2 = $this->myFunction;
$anonFunc2();
}
}
However, if I do the following (in another file, it errors saying undefined function () in... within the Apache error log.
//I'm using Yii framework, and this is getting the user
//objects instance variable 'myClass'.
$object = Yii::app()->user->myClass;
$object->TestCallAnon(); // **FAILS**
or
$func = $object->myFunction;
$func(); // ** ALSO FAILS **
In addition, several variations of calls to call_user_func and call_user_func_array don't work.
If anyone is able to offer any insight or help that would be great :).
Thanks in advance!
You can't pass references to functions around in PHP like you can in for instance JavaScript.
call_user_func has limited functionality. You can use it like so:
class MyClass {
function func() {}
static function func() {}
}
function myfunc() {}
$i = new MyClass();
call_user_func("myfunc", $args);
call_user_func(array($i, "func"), $args);
call_user_func(array(MyClass, "staticFunc"), $args);
I ended up solving this issue via a workaround that ended up being a better choice anyways.
In the end I ended up having a static class that had a method to randomly return one of the possible identifiers, and then another method which accepted that identifier to build the anonymous function upon each class.
Slightly less elegant than I would like but it ends up working well.
Thanks to everyone for your efforts.

PHP ambiguous statement when setting dynamic property value of class

I have a class called PreferenceCollection, which I load for a user into $_SESSION['Preferences'] once they log in to my web application. This simple class uses magic methods for getting and setting values. Here are the relevant parts:
class PreferenceCollection {
private $prefs;
function __construct() {
$this->prefs=Array();
}
function __get($var) {
return $this->prefs[$var];
}
function __set($var, $value) {
$this->prefs[$var]=$value;
$this->save();
}
}
Later on in my code, I have found it necessary to set the value of a dynamically chosen property. For this example, $key='pref_some_preference' and value='something'.
$_SESSION['Preferences']->substr($key, 5)=$value;
What I expect is the equivalent of $_SESSION['Preferences']->some_preference=$value. That is, the __set magic method will be called with the first parameter of some_preference, and the second parameter, $value.
Instead, this line gives me a fatal error:
PHP Fatal error: Can't use method return value in write context
I assume that PHP is interpreting that I want to set the return value of the substr() call to something, rather than setting the property.
Is my interpretation of what is happening correct? How would I get around this problem?
For now I am working around the issue with a public set method, but am curious how I could set that property directly.
I think you want
$_SESSION['Preferences']->{substr($key, 5)} = $value;
The braces {} are required to guide the PHP parser into the correct direction ;-) Given that $key is 12345test this would call __set('test', $value).

Categories