Trying to call unknow function - php

I have to dynamically try, if function is callable (not only if exists, but if is callable). This is my code:
try {
call_user_func($function, $arguments->arg);
} catch (Exception $e) {
$condition = $this->_object->getContent("phpCall", "return");
}
$function and $arguments->arg are dynamic variables, for example $function contains md5 and $arguments->arg contains 123.
I know that function md5 exists in PHP, but I get this error:
Warning: call_user_func() expects parameter 1 to be a valid callback, no array or string given in...
Any ideas?

Use is_callable
if (is_callable($function)){
//do stuff here
}
If you're going to pass it to call_user_func, make sure $function is a string.
Alternatively, you could just do:
$function($args);

Sounds like call_user_func expects a string with the name of the function to be called. Are you instead sending a function pointer?

Related

I get this error "Function name must be a string"

I have a PHP class where one of the private member is a callback to my log function (i.e. in PHP land, a function pointer is simply a string containing the name of the function to call).
self::$logferr = "msgfunc";
self::$logferr($res);
I get this error:
Fatal error: Function name must be a string
self::$logferr is equal to "msgfunc" which is my log function.
If I rewrite the code like this (on the same very class method):
$tmp = "msgfunc";
$tmp($res);
It works, the log function get called
Just wrap your variable in parenthesis, let PHP resolve the value first:
(self::$logferr)($res);
Proof of concept
You can use call_user_func. ref: this
call_user_func(self::$logferr, $res);
You should call it by using
self::{self::$logferr}($req)
Working example : https://3v4l.org/CYURS
Let's build a reproducible example:
class Foo {
private static $_loggerCallback;
static function setLogCallback(callable $loggerCallback) {
self::$_loggerCallback = $loggerCallback;
}
static function log(...$arguments) {
if (NULL !== self::$_loggerCallback) {
return self::$_loggerCallback(...$arguments);
}
return NULL;
}
}
Foo::setLogCallback(function() { echo 'success'; } );
Foo::log();
Output:
Notice: Undefined variable: _loggerCallback in /in/f3stL on line 13
Fatal error: Uncaught Error: Function name must be a string in /in/f3stL:13
The notice reports the actual mistake in this case. If you do not get something like it, you should check your error reporting configuration.
The notice shows that PHP looks for a local variable $_loggerCallback. It tries to execute $_loggerCallback(...$arguments). Here are different possibilities to make the call explicit.
Use parenthesis (PHP >= 7.0):
return (self::$_loggerCallback)(...$arguments);
Use a local variable (as you did):
$callback = self::$_loggerCallback;
return $callback(...$arguments);
A small advise. PHP support anonymous functions. You do not need a (global) function for a callback. This avoids calling to the function by name as well.

why pass-by-reference doesn't change the value of a variable?

$string='string';
function change(&$str){
$str='str';
}
call_user_func('change',$string);
echo $string;
output is 'string'. but $str refer to the $string , so change in $str should also change $string? why the value is still same?
It's not possible with call_user_func():
From the PHP documentation:
Note that the parameters for call_user_func() are not passed by reference.
That said you still can use call_user_func_array(). Using the reference becomes now possible. Here's the code you want:
function change(&$str)
{
$str='str';
}
$string='string';
$parameters = array(&$string);
call_user_func_array('change',$parameters);
echo $string;
However this solution is now Deprecated.
You still can get rid of call_user_func(), and simply do:
function change(&$str)
{
$str='str';
}
$string='string';
change($string);
echo $string;
http://php.net/manual/en/function.call-user-func.php
It clearly mention that the parameters for call_user_func() are not passed by reference.
Here's your error message:
<br />
<b>Warning</b>: Parameter 1 to change() expected to be a reference, value given on line <b>5</b>
because call_user_func does not pass parameters by reference.
Try run it like this:
$string='string';
function change(&$str){
$str='str';
}
change($string);
echo $string;
call_user_func doesn't pass by reference. From the PHP docs:
Note that the parameters for call_user_func() are not passed by reference.
(change($string), on the other hand, gives "str" as you would expect).
Further reading: Why does PHP's call_user_func() function not support passing by reference?

Only variables should be passed by reference

I have a class:
class Validator {
private $validationArray;
private $cleanedValues;
public function __construct($arg1, $arg2=NULL) {
if(empty($arg2)) {
$this->LoadValidatorByName($arg1);
} else {
$this->LoadValidatorFromLeadType($arg1, $arg2);
}
}
private function LoadValidatorFromLeadType($lead_type, $vocabulary) {
$ErrorReporter = new ErrorReporter;
$taxonomy_term = reset(taxonomy_get_term_by_name($lead_type, $vocabulary));
...some more stuff
The function taxonomy_get_term_by_name is a Drupal function but the issue I am experiencing is a PHP one.
When this method is called PHP complains with:
Strict warning: Only variables should be passed by reference in Validator->LoadValidatorFromLeadType() (line 32 of [path to my file])
Line 32 is ths line with:
$taxonomy_term = reset(taxonomy_get_term_by_name($lead_type, $vocabulary));
I've looked in to the error and I'm pretty sure I know what it means, but I can't understand what is wrong with my code that causes this warning.
reset is waiting for a variable reference. You are passing it a function result...
$taxonomy_term = taxonomy_get_term_by_name($lead_type, $vocabulary);
$taxonomy_term = reset($taxonomy_term );
This mean that only variable should be passed by reference, not an expression.
reset($array_variable); // correct
and
reset(some_function_that_returns_array()); // incorrect
If you take a second and think about it more - you would find that reset() with expression (not a variable) makes no sense, because you've rewind the array pointer to the beginning, but you don't have the ability to access that array anymore.
You should only reset a variable (which is passed by reference), not a return value of a function.
see: http://www.php.net/reset

PHP: Array passed by reference to a function?

I have this php function that has to perform some processing on a given array:
processArray($arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
Later, the code invokes the following:
$niceArray = array('key' => 'value');
processArray($niceArray);
The key 'helloStackOverflow' isn't available outside the processArray function. I tried calling the following:
processArray(&$niceArray);
Using "&" helps, however it raises some warning:
Deprecated function: Call-time pass-by-reference has been deprecated; If you would like to pass it by reference, modify the declaration of populateForm_withTextfields()
Tried the & in there, but that just stops the code.
How should I do this?
You have to define the reference in the function, not in the call to the function.
function processArray(&$arrayToProcess) {
processArray(&$arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
implements the reference in PHP way.
See http://fi2.php.net/references for useful information about references.
processArray(&$arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
Referencing passing now takes place at the function declaration, not when the function is called.
http://php.net/manual/en/language.references.pass.php
for full documentation.

PHP Basics: Can't deal with scope within classes

i got some trouble to understand scope in OOP. What i want is that $foo->test_item() prints "teststring"...Now it just fails with:
Warning: Missing argument 1 for testing::test_item()
Thanks a lot!
<?php
class testing {
public $vari = "teststring";
function test_item($vari){ //$this->vari doesn't work either
print $vari;
}
}
$foo = new testing();
$foo->test_item();
?>
test_item() should be:
function test_item() {
print $this->vari;
}
There is no need to pass $vari as a parameter.
Well, you've declared a method which expects an argument, which is missing. You should do:
$foo->test_item("Something");
As for the $this->, that goes inside of the class methods.
function test_item(){
print $this->vari;
}
function parameters can not be as "$this->var",
change your class like
class testing {
public $vari = "teststring";
function test_item(){ //$this->vari doesn't work either
print $this->vari;
}
}
$foo = new testing();
$foo->test_item();
And read this Object-Oriented PHP for Beginners
What's happening there is that $foo->test_item() is expecting something passed as an argument, so for example
$foo->test_item("Hello");
Would be correct in this case. This would print Hello
But, you may be wondering why it doesn't print teststring. This is because by calling
print $vari;
you are only printing the variable that has been passed to $foo->test_item()
However, if instead you do
function test_item(){ //notice I've removed the argument passed to test_item here...
print $this->vari;
}
You will instead be printing the value of the class property $vari. Use $this->... to call functions or variables within the scope of the class. If you try it without $this-> then PHP will look for that variable within the function's local scope

Categories