passing arguments with an array based object method call - php

I need to call a method from within a function, so I must pass it as an array like so:
array($this, 'display_page');
but I need to pass arguments along with it. Is this possible?
EDIT - New Method - Still not working.
I have now tried passing an anonymous function, in place of the array call back.
function(){MyClass::display_page($display);}
and edited the function thusly:
class MyClass{
static function display_page($arg = false)
{
if($arg){
echo $arg;
} else {
echo "Nothing to report!";
}
}
}
but all I get is Nothing to report!
EDIT The problem lies with the way the callback was being used within Wordpress (didn't think it was relevant, turns out it was). Have voted to close.

If you take a look at call_user_func, you can see that it has a second optional parameter called parameter.
mixed call_user_func ( callback $function [, mixed $parameter [, mixed $... ]] )
Use that.
Or you could do it the dirty way like mentioned in the comment on call_user_func
$method_name = "AMethodName";
$obj = new ClassName();
$obj->{$method_name}();

Maybe something along these lines will do:
class Foo {
public function callMe() {
$args = func_get_args();
var_dump($args);
}
public function getCallback() {
$that = $this;
return function ($oneMoreArg) use ($that) {
$that->callMe(1, 2, $oneMoreArg);
};
}
}
$foo = new Foo;
$callback = $foo->getCallback();
$callback(3);
If you're not running PHP 5.3, the best you can do is probably return a "custom callback array" and "custom call it":
$callback = array($this, 'callMe', 1, 2);
$args = array_splice($callback, 2);
$args[] = 3;
call_user_func_array($callback, $args);

Related

why is array(className,"privateFunctionName") returning the private function?

class someClass
{
public function truncate($content, $amount = false)
{
if (!$amount || preg_match_all("/\s+/", $content, $junk) <= $amount) return $content;
$content = preg_replace_callback("/(<\/?[^>]+\s+[^>]*>)/", array($this, '_shield'), $content);
......
return $truncate;
}
...
private function _shield($matches)
{
return preg_replace("/\s/", "\x01", $matches[0]);
}
...
private function _unshield($strings)
{
return preg_replace("/\x01/", " ", $strings);
}
...
}
According to PHP Manual, the 2nd parameter of preg_replace_callback should be a handler function, in the above code it is array($this, '_shield'), which I believe returns one of the class's private functions "_shield". Can someone explain to me why array(class,privateFunctionName) would return the private function? Is there a PHP manual page regarding this?
According to the manual, the second parameter should be a callable (as defined in the manual), and array($this, '_shield') is right that: it determines that $this->_shield() should be used as the function to handle the replacement
If you look at the examples for Callbacks / Callables you see the different ways to specify an object and class method array($object, 'method') and array('className', 'method').
If you're wanting to know why this works with private methods, it's because $this is the current object and of course has access to it's own private methods.
array('someDifferentClass', '_shield') and array($someDifferentObj, '_shield') would NOT work if _shield() was private in the other class.
You can also use anonymous functions:
$content = preg_replace_callback("/(<\/?[^>]+\s+[^>]*>)/",
function($v) {
return $this->_shield($v);
}, $content);
What got me here is array(1,2) would return an array [1,2], then why array($object, 'method') would return the method instead of an array with $object being its first element and string 'method' being the second?
It does return an array with $object being its first element and string 'method' being the second. But then preg_replace_callback uses those pieces of information in the array to call the method. You can do the same in PHP:
$method = array($this, '_shield');
$truncate = ${$method[0]}->{$method[1]}($content);

PHP method callback

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

Get PHP callable arguments as an array?

Say I have a callable stored as a variable:
$callable = function($foo = 'bar', $baz = ...) { return...; }
How would I get 'bar'?
if (is_callable($callable)) {
return func_get_args();
}
Unfortunately func_get_args() is for the current function, is it possible to get a key value pair of arguments?
You can use reflection:
$f = new ReflectionFunction($callable);
$params = $f->getParameters();
echo $params[0]->getDefaultValue();
You may want to use get_defined_vars to accomplish this, this function will return an array of all defined variables, specifically by accessing the callable index from the output array.
I came across this question because I was looking for getting the arguments for a callable which is not just the function itself. My case is
class MyClass{
public function f(){
// do some stuff
}
}
$myclass = new MyClass();
$callable = array($myclass, "f);
This is a valid callback in php. In this case the solution given by #Marek does not work.
I worked around with phps is_callable function. You can get the name of the function by using the third parameter. Then you have to check whether your callback is a function or a (class/object) method. Otherwise the Reflection-classes will mess up.
if($callable instanceof Closure){
$name = "";
is_callable($callable, false, $name);
if(strpos($name, "::") !== false){
$r = new ReflectionMethod($name);
}
else{
$r = new ReflectionFunction($name);
}
}
else{
$r = new ReflectionFunction($callable);
}
$parameters = $r->getParameters();
// ...
This also returns the correct value for ReflectionFunctionAbstract::isStatic() even though the $name always uses :: which normally indicates a static function (with some exceptions).
Note: In PHP>=7.0 this may be easier using Closures. There you can do someting like
$closure = Closure::fromCallable($callable);
$r = new ReflectionFunction($closure);
You may also cause have to distinguish between ReflectionFunction and ReflectionMethod but I can't test this because I am not using PHP>=7.0.

How to pass a reference to a callback function for use in array_filter with extra arguments?

The signature for my method looks like this:
public function ProgramRuleFilter(&$program, $today=null) {
When I invoke it like this,
$programs = array_filter($programs, array($this,'ProgramRuleFilter'));
Everything works as expected. The ProgramRuleFilter method updates the $program array and then returns true/false if it succeeded which correctly filters $programs.
However, now I want to pass an extra argument to the filter, $today. How can I do that?
I'm trying to invoke it like this:
$programs = array_filter($programs, new CallbackArgs(array($this,'ProgramRuleFilter'),$today));
Using this little class as a wrapper:
class CallbackArgs {
private $callback;
private $args;
function __construct() {
$args = func_get_args();
$this->callback = array_shift($args);
$this->args = $args;
}
function __invoke(&$arg) {
return call_user_func_array($this->callback, array_merge(array($arg),$this->args));
}
}
But the programs aren't being updated, so somewhere along the line it lost the reference to the original object. I'm not sure how to fix this.
The second argument to array_filter must be a callback; which means that array_filter itself will be calling your filter function. There is no way to tell array_filter to call that function in any other way, so you'll need to find a way to get the value of $today into your function some other way.
This is a perfect example of when to use a closure, which will let you bind some data (in this case, the value of $today) into a function / callback. Assuming you are using PHP 5.3 or later:
// Assuming $today has already been set
$object = $this; // PHP 5.4 eliminates the need for this
$programs = array_filter( $programs, function( $x ) use ( $today, $object ){
return $object->ProgramRuleFilter( $x, $today );
});
This defines a closure inline, using the values of $today and $object from the parent scope, and then just calls your existing function ProgramRuleFilter on that $object. (The somewhat unusual $object = $this gets around the fact that otherwise, the closure would not be able to call a method on your object instance. But in PHP 5.4, you can replace $object with $this inside the closure.)
Now, this is a somewhat inelegant way to do it, because all this closure does is hand off the work to the ProgramRuleFilter function. A better way would be to use the closure instead of the function. So:
// Assuming $today has already been set
$filter = function( $x ) use ( $today ){
// Cut and paste the contents of ProgramRuleFilter() here,
// and make it operate on $x and $today
};
$programs = array_filter( $programs, $filter );
Which variation works best for you will depend on the implementation of the rest of your app. Good luck!
I wrote a new method to handle it:
public static function array_filter_args($array, $callback) {
$args = array_slice(func_get_args(),2);
foreach($array as $key=>&$value) {
if(!call_user_func_array($callback, array_merge(array(&$value),$args))) {
unset($array[$key]);
}
}
return $array;
}
Called like this:
$programs = ArrayHelper::array_filter_args($programs, array($this,'ProgramRuleFilter'), $today);
I didn't know you could do this array(&$value), but I thought I'd try it, and it looks like it works. I'm guessing that array_merge is the culprit that dereferences the variable otherwise.

Is there a way to pass another parameter in the preg_replace_callback callback function?

mmmh guys, i really hope my english is good enaught to explain what i need.
Lets take this example (that is just an example!) of code:
class Something(){
public function Lower($string){
return strtolower($string);
}
}
class Foo{
public $something;
public $reg;
public $string;
public function __construct($reg, $string, $something){
$this->something = $something;
$this->reg = $reg;
$this->string = $string;
}
public function Replace(){
return preg_replace_callback($this->reg, 'Foo::Bar', $this->string);
}
public static function Bar($matches){
/*
* [...]
* do something with $matches and create the $output variable
* [...]
*/
/*
* I know is really useless in this example, but i need to have an istance to an object here
* (in this example, the Something object, but can be something else!)
*/
return $this->something->Lower($output);
}
}
$s = new Something();
$foo = new Foo($myregexp, $mystring, $s);
$content = $foo->Replace();
So, the php manual say that to use a class method as callback in preg_replace_callback(), the method must be abstract.
I need to pass an instance of a previuosly initialized object (in the example, an instance of the Something class) at the callback function.
I tryed to use call_user_func(), but doesnt work (becose in this way i miss the matches parameter).
Is there a way to do that, or have i to separate the process (doing before preg_match_all, for each match retrieve the replace value, and then a simple preg_replace)?
edit: as a side-note, before the tom haigh answer, i used this work-around (in the example, this is the Replace method):
$has_dynamic = preg_match_all($this->reg, $this->string, $dynamic);
if($has_dynamic){
/*
* The 'usefull' subset of my regexp is the third, so $dynamic[2]
*/
foreach($dynamic[2] AS $key => $value){
$dynamic['replaces'][$key] = $this->Bar($value);
}
/*
* ..but i need to replace the complete subset, so $dynamic[0]
*/
return str_replace($dynamic[0], $dynamic['replaces'], $this->string);
}else{
return $this->string;
}
Hope can help someone.
It is hard to pass arguments to callbacks, but instead of this:
return preg_replace_callback($this->reg, 'Foo::Bar', $this->string);
You could make Bar() not static, and use this:
return preg_replace_callback($this->reg, array($this, 'Bar'), $this->string);
Then the callback function will be able to see $this
See 'callback' in Pseudo-types and variables
Also in PHP >=5.3 you could use anonymous functions/closures to pass other data to callback functions.
I got stuck while trying to pass an argument (extra parameter) to a callback
with the create_function() and call_user_function() methods.
This is for reference:
<?php
$pattern = "/([MmT][a-z]*)/";
$string = "Mary is a naughty girl because she took all my animals.";
$kill = "Mary";
echo preg_replace_callback($pattern, function($ma) use ($kill) {
foreach ($ma as $m){
if ($m == $kill){
return "Jenny";
}
return "($m)";
}
}, $string);
echo "\n";
?>
$ php preg_replace_callback.php
Jenny is a naughty girl because she took all (my) ani(mals).
yes I use something like this to set and unset a changing variable so that it is available to the callback function and you don't need the newer php to do it:
foreach ($array as $key) {
$this->_current_key = $key;
preg_replace_callback($regex, array($this, '_callback'), $content);
unset($this->_current_key);
}
then in the callback function $this->_current_key is available:
function _callback ($match) {
//use the key to do something
new_array[$key] = $match[0];
//and still remove found string
return '';
}

Categories