Php callback with argument

When using a PHP function that requires a callback, how do we pass a custom parameter to the callback?

If we want to pass a custom parameter to the next_year callback function, how can we do that without using create_function()? Many thanks to you all.

depends on your version of php. Are you using php 5.3? If not, then create_function is the way to go.

@Jonathan Fingland: I am using PHP5.2, I am worried create_function() will slow down the match and replace process a lot because if it’s used, everytime preg_replace_callback is called, the callback function will always need to be created by create_function in runtime again.

4 Answers 4

I don’t know if it’s the easiest solution, but I’d go for a object-method callback, where the object carries the required parameters in its state:

class Callback < public $parameter; public function handle($matches) < return $matches[1] . ($matches[2] + $this->parameter); > > $instance = new Callback(); $instance->parameter = 99; echo preg_replace_callback("|(\d/\d/)(\d)|", array($instance, 'handle'), $text); 

Second option would be to resort to global variables:

$parameter = 99; function next_year($matches) < global $parameter; return $matches[1] . ($matches[2] + $parameter); >echo preg_replace_callback("|(\d/\d/)(\d)|", "next_year", $text); 

using a global variable is easier, but if I put that in a class as a static variable, is this thread safe?

PHP doesn’t have threads. Each PHP script runs in its own process. I would use the object instance method as in Gehrigs first example.

Читайте также:  Java list string constructor

I took S. Gehrigs idea and went a bit further with it, why not not put all the replacement functionality inside the class?

additional . $matches[1].($matches[2]+1); > public function replace_years($text) < return preg_replace_callback( "|(\d/\d/)(\d)|", array($this, 'next_year'), $text); > > $text = "April fools day is 04/01/2002\n"; $text.= "Last christmas was 12/24/2001\n"; $Replacer = new Replacer(); echo $Replacer->replace_years($text); 
[~]> php test.php April fools day is X04/01/2003 Last christmas was X12/24/2002 

Take a look at the callback pseudo-type, you can pass any variant of that to preg_replace_callback .

Here is an answer I gave yesterday, giving an overview of the type: Can you store a function in a PHP array?

The callback pseudo-type is just a string with the name of a function. So you can either declare the function like any other function and use that name just like you did. Or you use the create_function to declare a function on execution. create_function will then return the name of the newly created function lambda_ x . (Since PHP 5.3 you can also use the anonymouse function syntax.)

But since callback is just the name of a function, you could use a function to create that function on the fly and return the name of that newley created function like this:

function shift_years($years) < return create_function('$matches', 'return $matches[1].($matches[2]+'.((int)$years).');'); >$func = shift_years(123); echo preg_replace_callback("|(\d/\d/)(\d)|", $func, $text); 

Now shift_years creates your custom callback function as specified.

Источник

Callback with arguments lambda code example

So I want to move the logic of the callbacks to separate methods. Question: In PHP in order to define a callback a closure can be used and the tool for passing static parameters is the directive.

How to define a callback with parameters without closure and use in PHP?

In PHP in order to define a callback a closure can be used and the tool for passing static parameters is the use directive.

class MyClass < public function foo($x) < echo $x; >public function bar() < $x = '123'; $callback = function () use ($x) < $this->foo($x); >; $callback(); > > $myClass = new MyClass(); $myClass->bar(); 

Is it possible / How to avoid the anonymous function and replace it by a method?

class MyClass < public function foo($x) < echo $x; >public function baz() < $x = '567'; // There is no function with the name create_user_func. // Just to show, what I'm looking for. $callback = create_callback([$this, 'foo'], $params = [$x]); $callback(); >> $myClass = new MyClass(); $myClass->baz(); 

Some additional / backgroud info (to make clear, what I want to achieve and why — and to avoid misanderstandings):

In my concrete case I need to pass the callback to a method of a framework. That means: I cannot / may not affect the way it gets called.

The method accepts only the callback itself, no arguments for the callback. That means, the callback has to «know»/provide the static parameters (and their values) it needs.

It’s exactly, what the use directive solves. But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.

But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.

This is a perfect example for the magic method __invoke()

For each callback you need, extract the functionality and the properties it uses into a new class. Put the code into the __invoke() method of the new class, initialize all the properties it needs into its __construct() and you’re ready to go.

class MyClass < public function bar() < $x = '123'; // Create the callback, pass the values it needs to initialize $callback = new ActionFoo($x); // Call the callback without arguments $callback(); >> class ActionFoo < private $x; public function __construct($x) < $this->x = $x; > public function __invoke() < echo($this->x); > > $myClass = new MyClass(); $myClass->bar(); 

I guess it’s fair to say that you’re trying to emulate Javascript’s bind method. The problem with this in PHP is that functions are not first class citizens or objects, so something like ->bind($x) is not possible. There’s also no way to pass additional parameters for a callable . So you’re going to have to wrap it in something .

A more reusable method would be to write an appropriate class:

class CallbackWrapper < protected $callable, $args; public function __construct(callable $callable, array $args) < $this->callable = $callable; $this->args = $args; > public function __invoke() < call_user_func_array($this->callable, $this->args); > > giveMeACallback(new CallbackWrapper([$this, 'foo'], [$x])); 

Or you just simplify the construction of anonymous functions:

function make_callback(callable $callable, array $args) < return function () use ($callable, $args) < return call_user_func_array($callable, $args); >; > giveMeACallback(make_callback([$this, 'foo'], [$x])); 

There are many ways to achieve this.

class MyClass < private $x; public function foo() < echo $this->x; > public function bar() < $this->x = '123'; anon($this); > > $myClass = new MyClass(); $myClass->bar(); function anon($obj) < $obj->foo(); > 
class MyClass < private $x; public function foo() < echo $this->x; > public function bar() < $this->x = '123'; call_user_func([$this, 'foo']); > > $myClass = new MyClass(); $myClass->bar(); 
  1. If for some reason you don’t want to use member variables, you can pass the arguments with call_user_func_array .
class MyClass < private $x; public function foo($x) < echo $x; >public function bar() < $x = '123'; call_user_func_array([$this, 'foo'], [$x]); >> $myClass = new MyClass(); $myClass->bar(); 

Lambda — C++ for_each calling a vector of callback, The problem with the long example is that my_func(_1,s) is evaluated right there and then. You need to use std::bind (or boost::bind) to invoke the function on each element in the range. The alternative code that you posted does

How do I pass additional arguments to an event callback?

Is it possible to pass additional arguments to an event callback?

For example, if my event binding looked like this;

self.Bind(wx.EVT_BUTTON, self.do_something, self.button) 

How could I pass the arguments to my method?

self.do_something(self,event,arguments): """do something with arguments""" pass 

Use functools.partial , or in the general case a lambda expression.

The partial form would be

functools.partial(self.do_something, args) 

Note that in this case the event argument will be passed at the end of the argument list. The equivalent lambda form is:

lambda event: self.do_something(args, event) 
self.Bind(wx.EVT_BUTTON, lambda event, args=args: self.do_something(event, args), self.button) self.do_something(self,event,arguments): """do something with arguments""" pass 

It’s not clear when you want to provide these arguments, but if you want to provide them at Bind time (such that you can have a do_something which supports multiple uses), you can use functools.partial :

def do_something(self, arg, event): pass self.Bind(wx.EVT_BUTTON, functools.partial(self.do_something, arg), self.button) 

Then when do_something is called, it will be called with the arg you passed in to partial , as well as the event passed by the callback.

Use a lambda function. There’s some documentation on this on the wxPython wiki. I also wrote about it in my lambda tutorial. Here’s the lame example I created when I wrote that (which is in the article too):

import wx ######################################################################## class DemoFrame(wx.Frame): """ Frame that holds all other widgets """ #---------------------------------------------------------------------- def __init__(self): """Constructor""" wx.Frame.__init__(self, None, wx.ID_ANY, "wx lambda tutorial", size=(600,400) ) panel = wx.Panel(self) button8 = wx.Button(panel, label="8") button8.Bind(wx.EVT_BUTTON, lambda evt, name=button8.GetLabel(): self.onButton(evt, name)) button10 = wx.Button(panel, label="10") button10.Bind(wx.EVT_BUTTON, lambda evt, name=button10.GetLabel(): self.onButton(evt, name)) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(button8, 0, wx.ALL, 5) sizer.Add(button10, 0, wx.ALL, 5) panel.SetSizer(sizer) #---------------------------------------------------------------------- def onButton(self, event, buttonLabel): """""" print "You pressed the %s button!" % buttonLabel # Run the program if __name__ == "__main__": app = wx.App(False) frame = DemoFrame().Show() app.MainLoop() 

Android — Create a callback using a lambda, Then in your activity, create the callback as follows: val textChangeHandler = object: ITextWatcher < override fun onTextChanged (text: String) < var t = text >> And then setup your callback for your edittext controls as follows: my_edittext.onTextChange (textChangeHandler) Share. answered Jun …

Java 8 lambda expression callback type when parsing strings with regex

I would like to write a function, that can match a string against regex and execute a callback with all group matches as parameters.

I came up with this and it works:

 private static void parse(String source, String regex, Consumer callback) < //convert regex groups 1..n into integer array 0..n-1 and call //consumer callback with this array Matcher m = Pattern.compile(regex).matcher(source); String[] ret = new String[m.groupCount()]; if (m.matches()) < for (int i=0; icallback.accept(ret); > > 

parse(«Add 42,43», «Add (\\d+?),(\\d+?)», p -> processData(p[0],p[1]));

What I would like to be able to do ideally is this

parse(«Add 42,43», «Add (\\d+?),(\\d+?)», (x,y) -> processData(x,y));

What would be the most elegant way? The only one I can think of is to declare multiple functional interfaces with 1..n parameters and use overrides to handle it. Any better ideas, maybe with reflection?

As I understand the question is if there is a syntax sugar for tuple initialization from an array, i.e.:

 val (hour, minutes, seconds) = new String[]; 

. except for it is hidden inside a lambda arguments declaration.

As far as I know, there is no such syntax in Java 8 and your approach seems the most convenient. There is in Scala, however: Is there a way to initialize multiple variables from array or List in Scala?.

There are similar instructions in Scala as well:

 scala> val s = "Add 42,43" scala> val r = "Add (\\d+?),(\\d+?)".r scala> val r(x,y) = s x: String = 42 y: String = 43 

Since I solved it for myself by now, I will post a solution I came up with here. If someone proposes a better one, maybe with method chaining or more generic, I will gladly grant an answer.

You can use the class below like this:

Sring msg = "add:42,34"; ParseUtils.parse(msg, "add:(\\d+),(\\d+)", (int x,int y) -> simulator.add(x, y)); ParseUtils.parse(msg, "add:(\\d+),(\\d+)", simulator::add); //IntBiConsumer match ParseUtils.parse(msg, "add:(.*?),", System.out::println); 

And here is the class (I omitted trivial error processing and boolean returns if no match):

public class ParseUtils < @FunctionalInterface public interface Consumer < void accept(String s); >@FunctionalInterface public interface BiConsumer < void accept(String a, String b); >//. you can add TriConsumer etc. if you need to . @FunctionalInterface //conveniently parses integers public interface IntBiConsumer < void accept(int x, int y); >// implementations ----- public static void parse(String src, String regex, Consumer callback) < callback.accept(parse(src, regex)[0]); >public static void parse(String src, String regex, BiConsumer callback) < String[] p = parse(src, regex); callback.accept(p[0],p[1]); >public static void parse(String src, String regex, IntBiConsumer callback) < String[] p = parse(src, regex); callback.accept(Integer.parseInt(p[0]), Integer.parseInt(p[1])); >public static String[] parse(String source, String pattern) < Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(source); String[] ret = new String[m.groupCount()]; if (m.matches()) < for (int i=0; i> return ret; > > 

Wrapping C callbacks with C++ lambdas, possible to, Additionally, in each case, it should be possible for the function/functor/lambda to have either of the following signatures: int cb2args (int a, float b); int cb2args (int a, float b, float *c); I think this should be possible, and I got about 80% of the way there, but I’m stuck on template polymorphism based on …

Источник

Оцените статью