php call static function of class dynamically(function name is unknown) - php

Here is my Class:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
dd('hi');
}
public static function test2($a,$b)
{
dd('hi');
}
}
in another file I want to call one of the functions. So I included the file:
use App\Library\ProcessUploadedExcel;
the function is stored in a variable and when I use call_user_func_array I get an error:
ProcessUploadedExcel::test1(1,2);//works fine.
$func_name = 'test1';
call_user_func_array("ProcessUploadedExcel::" . $func_name, [1,2]);//gets error
error:
call_user_func_array() expects parameter 1 to be a valid callback,
class 'ProcessUploadedExcel' not found

You can do this:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
//dd('hi');
var_dump($a,$b);
}
public static function test2($a,$b)
{
dd('hi');
}
}
$func_name = 'test1';
ProcessUploadedExcel::$func_name(1,2);
Output:
int(1) int(2)
or if you want to use call_user_func_array()
call_user_func_array([ProcessUploadedExcel::class,$func_name],[1,2]);
Both solutions work properly with use and namespaces.

call_user_func_array ignores the use and you have to provide the full path:
$func_name = 'test1';
call_user_func_array("App\Library\ProcessUploadedExcel::" . $func_name, [1,2]);

You can try this way:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
echo ('hi');
}
public static function test2($a,$b)
{
echo ('hi');
}
}
$func_name = 'test1';
call_user_func_array([ ProcessUploadedExcel::class, $func_name ] , [1,2]);

First misconception is that you "included the file: use App\Library\ProcessUploadedExcel;". No, you just told PHP that whenever it encounters ProcessUploadedExcel, you actually mean App\Library\ProcessUploadedExcel. This doesn't include anything. Including something is a different mechanism using require or require_once. Actually including the file is done by the autoloader in most projects.
Now, you pass a string to call_user_func_array(). PHP doesn't look inside that string, so it can't tell that you mean something different than what you write there. Inside the called function, where the string is used, the above use ... is not effective, so the function fails since it can't find the according callback.
Remedies:
You could provide the fully qualified name "App\\Library\\ProcessUploadedExcel::test1" as parameter.
You could make PHP look up the fully qualified name for you using ProcessUploadedExcel::class . "::test1".
I'm not sure that either of these works though, but check the documentation which way to specify a callback exist. Maybe you need to specify class and function separately like [ProcessUploadedExcel::class, "test1"].

Related

Use PHP value as function name to get dynamic function [duplicate]

Is there a way to call a function through variables?
For instance, I want to call the function Login(). Can I do this:
$varFunction = "Login"; //to call the function
Can I use $varFunction?
Yes, you can:
$varFunction();
Or:
call_user_func($varFunction);
Ensure that you validate $varFunction for malicious input.
For your modules, consider something like this (depending on your actual needs):
abstract class ModuleBase {
public function main() {
echo 'main on base';
}
}
class ModuleA extends ModuleBase {
public function main() {
parent::main();
echo 'a';
}
}
class ModuleB extends ModuleBase {
public function main() {
parent::main();
echo 'b';
}
}
function runModuleMain(ModuleBase $module) {
$module->main();
}
And then call runModuleMain() with the correct module instance.
You can use...
$varFunction = "Login";
$varFunction();
...and it goes without saying to make sure that the variable is trusted.
<?php
$fxname = 'helloWorld';
function helloWorld(){
echo "What a beautiful world!";
}
$fxname(); //echos What a beautiful world!
?>
I successfully call the function as follows:
$methodName = 'Login';
$classInstance = new ClassName();
$classInstance->$methodName($arg1, $arg2, $arg3);
It works with PHP 5.3.0+
I'm also working in Laravel.
If it's in the same class:
$funcName = 'Login';
// Without arguments:
$this->$funcName();
// With arguments:
$this->$funcName($arg1, $arg2);
// Also acceptable:
$this->{$funcName}($arg1, $arg2)
If it's in a different class:
$someClass = new SomeClass(); // create new if it doesn't already exist in a variable
$someClass->$funcName($arg1, $arg2);
// Also acceptable:
$someClass->{$funcName}($arg1, $arg2)
Tip:
If the function name is dynamic as well:
$step = 2;
$this->{'handleStep' . $step}($arg1, $arg2);
// or
$someClass->{'handleStep' . $step}($arg1, $arg2);
This will call handleStep1(), handleStep2(), etc. depending on the value of $step.
You really should consider using classes for modules, as this would allow you to both have consistent code structure and keep method names identical for several modules. This will also give you the flexibility in inheriting or changing the code for every module.
On the topic, other than calling methods as stated above (that is, using variables as function names, or call_user_func_* functions family), starting with PHP 5.3 you can use closures that are dynamic anonymous functions, which could provide you with an alternative way to do what you want.

How to Pass a function to a class in php

I have a class that generates data based on a few things. I would like to format that data from the outside. So I am trying to pass a function into the class so that it would format that data. I have looked at many examples, but it seems this is unique.
Can anybody give an idea of how to do this? The following code gives an error.
<?php
class someClass {
var $outsideFunc; // placeholder for function to be defined from outside
var $somevar='Me'; // generated text
function echoarg($abc){
$outsideFunc=$this->outsideFunc; // bring the outside function in
call_user_func($outsideFunc,$abc); // execute outside function on text
echo $abc;
}
}
function outsidefunc($param){ // define custom function
$param='I am '.$param;
}
$someClass=new someClass();
$someClass -> outsideFunc = 'outsideFunc'; // send custom function into Class
$someClass -> echoarg($someClass->somevar);
$someClass -> outsidefunc = 'outsidefunc';
In PHP, function names are not case sensitive, yet object property names are. You need $someClass->outsideFunc, not $someClass->outsidefunc.
Note that good OOP design practice calls for the use of getter and setter methods rather than just accessing properties directly from outside code. Also note that PHP 5.3 introduced support for anonymous functions.
Yeah. You are right. Now there is no error. But it does not work either.
By default, PHP does not pass arguments by reference; outsidefunc() does not actually do anything useful. If you want it to set $param in the caller to something else, and do not want to just return the new value, you could change the function signature to look like this:
function outsidefunc(&$param) {
You would also need to change the way you call the function, as call_user_func() does not allow you to pass arguments by reference. Either of these ways should work:
$outsideFunc($abc);
call_user_func_array($outsideFunc, array(&$abc));
Why not pass your function as an argument?
<?php
class someClass {
public $somevar="Me";
public function echoarg($abc,$cb=null) {
if( $cb) $cb($abc);
echo $abc;
}
}
$someClass = new someClass();
$someClass->echoarg($someClass->somevar,function(&$a) {$a = "I am ".$a;});
i am not sure what exactly you are looking for, but what i get is, you want to pass object in a function which can be acheive by
Type Hinting in PHP.
class MyClass {
public $var = 'Hello World';
}
function myFunction(MyClass $foo) {
echo $foo->var;
}
$myclass = new MyClass;
myFunction($myclass);
OP, perhaps closures are what you're looking for?
It doesn't do EXACTLY what you're looking for (actually add function to class), but can be added to a class variable and executed like any normal anonymous function.
$myClass->addFunc(function($arg) { return 'test: ' . $arg });
$myClass->execFunc(0);
class myClass {
protected $funcs;
public function addFunc(closure $func) {
$this->funcs[] = $func;
}
public function execFunc($index) { $this->funcs[$index](); } // obviously, do some checking here first.
}

How can I use a callback function which is stored as a class member in PHP?

Consider the following code, which is a scheme of storing a callback function as a member, and then using it:
class MyClass {
function __construct($callback) {
$this->callback = $callback;
}
function makeCall() {
return $this->callback();
}
}
function myFunc() {
return 'myFunc was here';
}
$o = new MyClass(myFunc);
echo $o->makeCall();
I would expect myFunc was here to be echoed, but instead I get:
Call to undefined method MyClass::callback()
Can anyone explain what's wrong here, and what I can do in order to get the desired behaviour?
In case it matters, I am using PHP 5.3.13.
You can change your makeCall method to this:
function makeCall() {
$func = $this->callback;
return $func();
}
Pass it as a string and call it by call_user_func.
class MyClass {
function __construct($callback) {
$this->callback = $callback;
}
function makeCall() {
return call_user_func($this->callback);
}
}
function myFunc() {
return 'myFunc was here';
}
$o = new MyClass("myFunc");
echo $o->makeCall();
One important thing about PHP is that it recognises the type of a symbol with the syntax rather than the contents of it, so you need to state explicitly what you refer to.
In many languages you just write:
myVariable
myFunction
myConstant
myClass
myClass.myStaticMethod
myObject.myMethod
And the parser/compiler knows what each of the symbols means, because it's aware of what they refer to simply by knowing what's assigned to them.
In PHP, however, you need to use the syntax to let the parser know what "symbol namespace" you refer to, so normally you write:
$myVariable
myFunction()
myConstant
new myClass
myClass::myStaticMethod()
$myObject->method()
However, as you can see these are calls rather than references. To pass a reference to a function, class or method in PHP, combined string and array syntax is used:
'myFunction'
array('myClass', 'myStaticMethod')
array($myObject, 'myMethod')
In your case, you need to use 'myFunc' in place of myFunc to let PHP know that you're passing a reference to a function and not retrieving the value the myFunc constant.
Another ramification is that when you write $myObject->callback(), PHP assumes callback is a method because of the parentheses and it does not attempt to loop up a property.
To achieve the expected result, you need to either store a copy of/reference to the property callback in a local variable and use the following syntax:
$callback = $this->callback;
return $callback();
which identifies it as a closure, because of the dollar sign and the parentheses; or call it with the call_user_func function:
call_user_func($this->callback);
which, on the other hand, is a built-in function that expects callback.

how can i include php file in php class

i have php with an array i.e
$var = array(
"var" => "var value",
"var2" => "var value1"
);
and have another file with a class i.e
class class1{
function fnc1(){
echo $var['var2'];
//rest of function here
}
}
now how can i get $var['var'] in class file in function fnc1()
You can pass it as an argument, or use the global keyword to put it in the current scope.
However, using global is discouraged, try passing it as an argument.
Pass it as an argument?
class class1{
function fnc1($var) {
echo $var['var2'];
}
}
And in your other file call this class method with your array as an argument.
From: http://php.net/manual/en/function.include.php
When a file is included, the code it contains inherits the variable scope of the line on which the include occurs. Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.
So you could do
class class1
{
function fnc1()
{
include 'thefile.php'
echo $var['var2'];
//rest of function here
}
}
but like others pointed out before, you dont want to do that, because it introduces a dependency on the filesystem in your class. If your method requires those variables to work, then inject them as method arguments or pass them into the constructor and make them a property (if you need them more often). This is called Dependency Injection and it will make your code much more maintainable in the long run, e.g. do
class class1
{
private $data;
public function __construct(array $var)
{
$this->data = $var;
}
function fnc1()
{
echo $this->data['var2'];
//rest of function here
}
}
and then do
$obj = new class1($var);
echo $obj->fnc1();
or require the data to be passed into the method on invocation
class class1
{
function fnc1(array $var)
{
echo $var['var2'];
//rest of function here
}
}
and then
$obj = new class1;
$obj->fnc1($var);
You might use global $var in your included file, but it's really a bad practice, as another script, before your included file, might redefine the value/type of $var.
Example :
class class1{
function fnc1(){
global $var;
echo $var['var2'];
//rest of function here
}
}
A better solution, is to pass your $var as a parameter to your fnc1(), even to your class1::__construct()
#Vindia: I'd prefer the argumant-style too, but would recommend either using type hint or a simple check to avoid warnings when accessing *non_array*['var2']:
// acccepts array only. Errors be handled outside
function fnc1(Array $var) {
echo $var['var2'];
}
// accepts any type:
function fnc1(Array $var) {
if (is_array($var)) {
echo $var['var2'];
}
}
class class1{
function fnc1(){
include 'otherFile.php';
echo $var['var2'];
//rest of function here
}
}

Call a PHP function dynamically

Is there a way to call a function through variables?
For instance, I want to call the function Login(). Can I do this:
$varFunction = "Login"; //to call the function
Can I use $varFunction?
Yes, you can:
$varFunction();
Or:
call_user_func($varFunction);
Ensure that you validate $varFunction for malicious input.
For your modules, consider something like this (depending on your actual needs):
abstract class ModuleBase {
public function main() {
echo 'main on base';
}
}
class ModuleA extends ModuleBase {
public function main() {
parent::main();
echo 'a';
}
}
class ModuleB extends ModuleBase {
public function main() {
parent::main();
echo 'b';
}
}
function runModuleMain(ModuleBase $module) {
$module->main();
}
And then call runModuleMain() with the correct module instance.
You can use...
$varFunction = "Login";
$varFunction();
...and it goes without saying to make sure that the variable is trusted.
<?php
$fxname = 'helloWorld';
function helloWorld(){
echo "What a beautiful world!";
}
$fxname(); //echos What a beautiful world!
?>
I successfully call the function as follows:
$methodName = 'Login';
$classInstance = new ClassName();
$classInstance->$methodName($arg1, $arg2, $arg3);
It works with PHP 5.3.0+
I'm also working in Laravel.
If it's in the same class:
$funcName = 'Login';
// Without arguments:
$this->$funcName();
// With arguments:
$this->$funcName($arg1, $arg2);
// Also acceptable:
$this->{$funcName}($arg1, $arg2)
If it's in a different class:
$someClass = new SomeClass(); // create new if it doesn't already exist in a variable
$someClass->$funcName($arg1, $arg2);
// Also acceptable:
$someClass->{$funcName}($arg1, $arg2)
Tip:
If the function name is dynamic as well:
$step = 2;
$this->{'handleStep' . $step}($arg1, $arg2);
// or
$someClass->{'handleStep' . $step}($arg1, $arg2);
This will call handleStep1(), handleStep2(), etc. depending on the value of $step.
You really should consider using classes for modules, as this would allow you to both have consistent code structure and keep method names identical for several modules. This will also give you the flexibility in inheriting or changing the code for every module.
On the topic, other than calling methods as stated above (that is, using variables as function names, or call_user_func_* functions family), starting with PHP 5.3 you can use closures that are dynamic anonymous functions, which could provide you with an alternative way to do what you want.

Categories