Let say, I have a class like this:
<?php
class ExampleClass {
public function callerOne($arg1, $arg2) {
return $this->calledMethod(function($arg1, $arg2) {
// do something
});
}
public function callerTwo($arg1) {
return $this->calledMethod(function($arg1) {
// do something
});
}
protected function calledMethod(Closure $closure)
{
// How to access caller's arguments, like func_get_args()
$args = get_caller_method_args();
return call_user_func_array($closure, $args);
}
}
In above example, method calledMethod wrap the passed closure in something, e.g. warp it between beginTransaction() and endTransaction(), but I need to access the caller method arguments.
I know that a possible solution would be using use statement when passing closure to calledMethod(), but it would be much easier on eye if what I wanted is possible.
How can I access to the caller's arguments, inside called method? Is that even possible?
I'm not sure if this helps in your case, but you can create ReflectionFunction and use ReflectionFunction::invokeArgs, which invokes the function and pass its arguments as array.
<?php
$closure = function () {
echo 'Hello to: ' . implode(', ', func_get_args()) . PHP_EOL;
};
$reflection = new ReflectionFunction($closure);
// This will output: "Hello to: foo, bar, baz"
$reflection->invokeArgs(array('foo', 'bar', 'baz'));
Related
To be more exact, the "callable" used in function declaration arguments. like the one below.
function post($pattern, callable $handler) {
$this->routes['post'][$pattern] = $handler;
return $this;
}
How does it benefit us?
why and how do we use it?
Maybe this is very basic for you, however, I've tried searching for it and I was getting no answers. at least, nothing I could understand.
Hoping for a for-dummies answer. I'm new to coding... XD
Edit: Here's a link to where I copied the above piece of code from: link
The callable type allows us to pass a callback function to the function that is being called. That is, callback function parameters allow the function being called to dynamically call code that we specify in the callable function parameter. This is useful because it allows us to pass dynamic code to be executed to a function.
For example, one might want to call a function and the function accepts a callback function called log, which would log data in a custom way that you want.
I hope that makes sense. For details, see this link.
It's a type hinting which tells us this function accepts the parameter $handler as a function, see this example to clarify things:
function helloWorld()
{
echo 'Hello World!';
}
function handle(callable $fn)
{
$fn(); // We know the parameter is callable then we execute the function.
}
handle('helloWorld'); // Outputs: Hello World!
It's a very simple example, But I hope it helps you understand the idea.
Here is example use of using a callable as a parameter.
The wait_do_linebreak function below will sleep for a given time, then call a function with the tailing parameters given, and then echo a line break.
...$params packs the tailing parameters into an array called $params. Here it's being used to proxy arguments into the callables.
At the end of the examples you'll see a native function that takes a callable as a parameter.
<?php
function wait_do_linebreak($time, callable $something, ...$params)
{
sleep($time);
call_user_func_array($something, $params);
echo "\n";
}
function earth_greeting() {
echo 'hello earth';
}
class Echo_Two
{
public function __invoke($baz, $bat)
{
echo $baz, " ", $bat;
}
}
class Eat_Static
{
static function another()
{
echo 'Another example.';
}
}
class Foo
{
public function more()
{
echo 'And here is another one.';
}
}
wait_do_linebreak(0, 'earth_greeting');
$my_echo = function($str) {
echo $str;
};
wait_do_linebreak(0, $my_echo, 'hello');
wait_do_linebreak(0, function() {
echo "I'm on top of the world.";
});
wait_do_linebreak(0, new Echo_Two, 'The', 'Earth');
wait_do_linebreak(0, ['Eat_Static', 'another']);
wait_do_linebreak(0, [new Foo, 'more']);
$array = [
'jim',
'bones',
'spock'
];
$word_contains_o = function (string $str) {
return strpos($str, 'o') !== false;
};
print_r(array_filter($array, $word_contains_o));
Output:
hello earth
hello
I'm on top of the world.
The Earth
Another example.
And here is another one.
Array
(
[1] => bones
[2] => spock
)
A callable (callback) function is a function that is called inside another function or used as a parameter of another function
// An example callback function
function my_callback_function() {
echo 'hello world!';
}
// Type 1: Simple callback
call_user_func('my_callback_function');
There are some cases that your function is a template for other functions, in that case, you use parameters for the callable function.
for more information:
http://php.net/manual/en/language.types.callable.php
Callable
callable is a php data type. It simply means anything which can be called i.e. a function type. If this function is a closure, static/regular method or something else doesn't matter as long as we can call the function.
Example:
//php callable type
$callback = function() {
return "hello world!\n";
};
class MyClass {
static function myCallbackMethod() {
return "static method call \n";
}
public function cb()
{
return "method call \n";
}
public function __invoke() {
return "invoke \n";
}
}
$obj = new MyClass();
// Illustrative function
function soUseful (callable $callback) {
echo $callback();
}
soUseful($callback);
soUseful(array($obj, 'cb')); // syntax for making method callable
soUseful(array('MyClass', 'myCallbackMethod')); // syntax for making static method callable
soUseful($obj); // Object can be made callable via __invoke()
soUseful(fn() => "hi from closure \n"); // arrow fn
//Output
//hello world!
//method call
//static method call
//invoke
//hi from closure
Callable is a data-type.
note: You can always check whether your variables are of type "callable" by using the built-in is_callable function, giving your variable's handler as its argument.
The "callable" keyword seen in the code, is used for a "Type declaration", also known as "type hint" in PHP 5. this is used to specify which type of argument or parameter your functions or methods accept. this is done by simply putting the "type hint" or "Type declaration" (i.e. the name of the type, like in this case, "callable") before the parameter names.
Whenever using "type hints" or "Type declarations" for your function declarations (i.e. when you've specified which types are allowed/accepted), and you're calling them giving parameters of data-types other than those specified as acceptable, an error is generated.
note: also, class names can be used if you would like to make your function require > an object instantiated from a specific class < for its respective parameter
-
References:
php manual > type-declaration
php manual > callable type
-
I'm new to coding so please correct my mistakes :)
Use callable to require a callback function as an argument
We use it with argument of function it will strict to to pass callable( closure static/regular function ) when we calling the function
Example 1 not Passing a Callable in function call :
$myfuntion = function(callable $sum){
};
// when calling myfuntion i passed integer
$myfuntion(123);
// it will not allow us to do this
Example 2 Passing Callable in function call :
$sum = function($arr){
echo array_sum($arr);
};
$myfuntion = function(callable $sum){
// do something
};
$myfuntion($sum);
// Sum is a callable function now it will work absolutely fine
Proper Example :
$sum = function( ...$args){
echo array_sum($args);
};
$myfun = function(callable $sum){
$sum(1,2,3,4,5);
};
$myfun($sum);
How to pass method callback as a parameter to another method? All the examples I've seen use functions, but not methods. What I've tried is:
call_user_func($this, 'method_name', [$param1, $param2,...]);
Also is there another, more elegant way, like just passing $this->method_name as a parameter?
I know I could add the callback as:
function () use ($param1, $param2,...) {
return $this->method_name($param1, $param2);
}
But I would like to omit the closure part.
You could also use [$obj, 'method'] as an callback, bind to an object.
class A {
public $b = 'test';
public function callback() {
echo $this->b;
}
}
$a = new A();
$f = [$a, 'callback'];
$f();
I would like to have an array of methods in my php class, indexed with method names, so that I can do something like this:
public function executeMethod($methodName){
$method=$this->methodArray[$methodName];
$this->$method();
// or some other way to call a method whose name is stored in variable $methodName
}
I've found this for __call:
The overloading methods are invoked when interacting with properties
or methods that have not been declared or are not visible in the
current scope
However, methods I'd like to use in executeMethod are visible.
What is proper way to do that? Is it possible?
EDIT: I wanted to get a method name in the executeMethod, and then call the method of the given name, and had an idea of methods array.
you can call object methods and properties by using string with syntax
$method = 'your_method_name_as_string';
$this->$method();
from php doc
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // This calls the Bar() method
}
function Bar()
{
echo "This is Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // This calls $foo->Variable()
?>
Maybe you are looking for something like this:
public function executeMethod($methodName) {
if (isset($this->methodArray[$methodName])) {
$method = $this->methodArray[$methodName];
return call_user_func(array($this, $method));
}
throw new Exception("There is no such method!");
}
anonymous functions are available in php 5.3
i think you're trying to do something like
$tmp['doo'] = function() { echo "DOO"; };
$tmp['foo'] = function() { echo "FOO"; };
$tmp['goo'] = function() { echo "GOO"; };
$tmp['doo']();
Let's say I have a class with 10 methods, each method has different parameters.
I want to log input parameters of all methods of said class without having to do edit each method to insert that logging code. Is there away to do that ?
Just wrap it with decorator with magic __call http://ideone.com/n9ZUD
class TargetClass
{
public function A($a, $b) {}
public function B($c, $d) {}
public function C($e, $f) {}
}
class LoggingDecorator
{
private $_target;
public function __construct($target)
{
$this->_target = $target;
}
public function __call($name, $params)
{
$this->_log($name, $params);
return call_user_func_array(array($this->_target, $name), $params);
}
private function _log($name, $params)
{
echo $name . ' has been called with params: ' . implode(', ', $params) . '<br>';
}
}
$target = new TargetClass();
$logger = new LoggingDecorator($target);
$logger->A(1, 2);
$logger->A(3, 4);
The only disadvantage of this approach is that you will lose the type of the decorated class, e.g. you won't be able to satisfy type hints with it. If that is a concern, distill the interface of TargetClass and implement it in the LoggingDecorator.
Not directly, no.
You could rename all your methods to have an underscore suffix, e.g.:
myFunction() -> _myFunction()
Then, write add the magic __call() method to intercept calls to the previous (unprefixed) methods. Then you would log the request and pass on all arguments to the original method.
It's kind of ugly and still requires a change to all your method names.
I might be over simplifying this - but you can retrieve all the arguments of a function using
func_get_args();
Returns an array comprising a function's argument list
http://www.php.net/manual/en/function.func-get-args.php
<?php
function foo() {
$args = func_get_args();
var_export($args);
}
foo('arg1', 'arg1');
?>
That would output something like this -
array (
0 => 'arg1',
1 => 'arg2',
)
There are a few notes to be added here - you should read the documentation link I provided - one "limitation" is -
Note:
This function returns a copy of the passed arguments only, and does not account for default (non-passed) arguments.
I would like to implement something similar to a c# delegate method in PHP. A quick word to explain what I'm trying to do overall: I am trying to implement some asynchronous functionality. Basically, some resource-intensive calls that get queued, cached and dispatched when the underlying system gets around to it. When the asynchronous call finally receives a response I would like a callback event to be raised.
I am having some problems coming up with a mechanism to do callbacks in PHP. I have come up with a method that works for now but I am unhappy with it. Basically, it involves passing a reference to the object and the name of the method on it that will serve as the callback (taking the response as an argument) and then use eval to call the method when need be. This is sub-optimal for a variety of reasons, is there a better way of doing this that anyone knows of?
(Apart from the observer pattern) you can also use call_user_func() or call_user_func_array().
If you pass an array(obj, methodname) as first parameter it will invoked as $obj->methodname().
<?php
class Foo {
public function bar($x) {
echo $x;
}
}
function xyz($cb) {
$value = rand(1,100);
call_user_func($cb, $value);
}
$foo = new Foo;
xyz( array($foo, 'bar') );
?>
How do you feel about using the Observer pattern? If not, you can implement a true callback this way:
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
I was wondering if we could use __invoke magic method to create "kind of" first class function and thus implement a callback
Sound something like that, for PHP 5.3
interface Callback
{
public function __invoke();
}
class MyCallback implements Callback
{
private function sayHello () { echo "Hello"; }
public function __invoke () { $this->sayHello(); }
}
class MySecondCallback implements Callback
{
private function sayThere () { echo "World"; }
public function __invoke () { $this->sayThere(); }
}
class WhatToPrint
{
protected $callbacks = array();
public function register (Callback $callback)
{
$this->callbacks[] = $callback;
return $this;
}
public function saySomething ()
{
foreach ($this->callbacks as $callback) $callback();
}
}
$first_callback = new MyCallback;
$second_callback = new MySecondCallback;
$wrapper = new WhatToPrint;
$wrapper->register($first_callback)->register($second_callback)->saySomething();
Will print HelloWorld
Hope it'll help ;)
But I'd prefer the Controller pattern with SPL for such a feature.