Argument Forwarding in PHP - php

Consider the following functions:
function debug() {
$args = func_get_args();
// process $args
}
function debug_die() {
// call debug() with the passed arguments
die;
}
The method debug_die exits after calling debug that takes a variable number of arguments.
So the arguments passed to debug_die as such are meant for debug only and just have to be forwarded. How can this be done in the debug_die method?

function debug_die() {
call_user_func_array("debug", func_get_args());
die;
}

Related

What does the keyword "callable" do in PHP

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);

PHP Nested call_user_func_array with classes

I have a complicated scenario based on an existing framework I'm using which is forcing me to deal with nested call_user_func_array calls. I've got a file with two functions:
function their_caller($options)
{
call_user_func_array('their_callback', $options);
}
function their_callback($options)
{
call_user_func_array($options[0], $options[1]);
}
Then I have another file with a class with and some public methods:
namespace FOO;
class MyClass
{
public function my_caller()
{
$operations = array(
array(
array($this, 'my_callback'),
'Hello World'
)
);
their_caller($operations);
}
public function my_callback($text)
{
print $text;
}
}
When I call my_caller() on a new instance of MyClass, it calls their_caller which then passes an array of arguments containing a reference to MyClass (as $this) as well as the method my_callback.
their_caller() then forwards the request to their_callback and passes $options along.
In their_callback I can debug $options[0] and see that it's an array containing a reference to MyClass and my_callback.
I call get_class_methods() on $options[0][0] in their_callback and it will show the list of methods, but for some reason, call_user_func_array($options[0], $options[1]); won't call my_callback on MyClass. I can even call $options[0][0]->my_callback('HELLO'); and it works.
Unfortunately, I can't modify their_caller or their_callback. They are part of the framework. Any ideas what's preventing it from working?
Note: Your function their_callback will receive two arguments.
Try this code snippet here
<?php
ini_set('display_errors', 1);
function their_caller($options)
{
call_user_func_array('their_callback', $options);
}
//first argument will receive callback
//second argument will receive the text which you want to send as argument.
function their_callback($callback,$option)
{
//call_user_func_array should expect second argument as array not string.
call_user_func_array($callback, array($option));
//here we have converted `$option` string(Hello World) to array.
}
class MyClass
{
public function my_caller()
{
$operations = array(
array(
array($this, 'my_callback'),
'Hello World'
)
);
call_user_func_array('their_caller', $operations);
}
public function my_callback($text)
{
print $text;
}
}
$object= new MyClass();
$object->my_caller();

Getting a Calling Function's Arguments in PHP

I'm working on a logging class, and I'd like to add a convenience function which would log the arguments of the function from which it is called. A little convoluted, so here's some code:
function MyFunc($arg1, $arg2) {
global $oLog;
$oLog->logArgs();
}
So, I can get the name of the calling function (MyFunc) using debug_backtrace(). I'd be interested in getting the names and values of the arguments, preferably without having to add func_get_args() in the call to logArgs().
I know it's a tall order, but PHP continues to surprise me, so I'm putting it out there, just in case.
Thanks.
You can do this with reflection:
function logger()
{
$bt = debug_backtrace();
$previous = $bt[1];
if(empty($previous['class'])) {
$fn = new ReflectionFunction($previous['function']);
} else {
$class = new ReflectionClass($previous['class']);
$fn = $class->getMethod($previous['function']);
}
$parameters = $fn->getParameters();
//Get a parameter name with $parameters[$paramNum]->getName()
//Get the value from $previous['args'][$paramNum]
}
This particular implementation won't work with closures, but it will work with both global functions and class methods.

Pass-by-reference for functions with varying length of functions

I have a function with optional number of arguments, something like this:
function DoSomething()
{
$args = funct_get_args();
// and the rest of function
}
In the function above, how can I define the first argument to be passed by reference?
So when I calling it, I be able to do so:
DoSomething(&$first, $second, $third);
Simply declare it in the parameter list:
function DoSomething(&$first) {
$args = func_get_args();
// and the rest of function
}
DoSomething($first, $second, $third);

passing multiple arguments to function php

Apologies for the newbie question but i have a function that takes two parameters one is an array one is a variable function createList($array, $var) {}. I have another function which calls createList with only one parameter, the $var, doSomething($var); it does not contain a local copy of the array. How can I just pass in one parameter to a function which expects two in PHP?
attempt at solution :
function createList (array $args = array()) {
//how do i define the array without iterating through it?
$args += $array;
$args += $var;
}
If you can get your hands on PHP 5.6+, there's a new syntax for variable arguments: the ellipsis keyword.
It simply converts all the arguments to an array.
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
Doc: ... in PHP 5.6+
You have a couple of options here.
First is to use optional parameters.
function myFunction($needThis, $needThisToo, $optional=null) {
/** do something cool **/
}
The other way is just to avoid naming any parameters (this method is not preferred because editors can't hint at anything and there is no documentation in the method signature).
function myFunction() {
$args = func_get_args();
/** now you can access these as $args[0], $args[1] **/
}
You can specify no parameters in your function declaration, then use PHP's func_get_arg or func_get_args to get the arguments.
function createList() {
$arg1 = func_get_arg(0);
//Do some type checking to see which argument it is.
//check if there is another argument with func_num_args.
//Do something with the second arg.
}

Categories