Something like a callback delegate function in php - php

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.

Related

How to call an function automatically when I call an member functions of class?

In php is there any possible way to call an new function automatically while calling a member function of the class
For Example : I have writing a class with 4 member functions .
And then I have created the object for that class.
Now I am going to call any one of the function as I needed .
When I call an any one of the function of that class . I needed to do some set/Logic , how can I do this
Note: I am not willing to call an new function inside the defined functions and also not need to write a logic for all defined functions . I am looking for any magic methods . Please advice me
Class IMAP{
Function IMAP()
{
Do something
}
Function getfolders() {
Do something
}
Function appendmessage()
{
Do something
}
//I need to call the below function whenever I am going to call any one of the function
Function checktokenexpired()
{
}
}
This class contains lot functions I am not possible to add this function in all functions
If you don't want a full-blown AOP library, you can start with a small wrapper like this:
class AOP
{
function __construct($base, $methods) {
$this->base = $base;
$this->methods = $methods;
}
function __call($name, $args) {
$this->methods["before_$name"]($args);
$ret = call_user_func_array([$this->base, $name], $args);
$this->methods["after_$name"]($ret);
return $ret;
}
}
Usage like this:
class Foo
{
function bar() {
echo "bar \n";
}
}
$foo = new AOP(new Foo, [
'before_bar' => function() { echo "BEFORE\n"; },
'after_bar' => function() { echo "AFTER\n"; },
]);
$foo->bar(); // prints BEFORE...bar...AFTER
You should look at PHP magic function __call which allows you to implement method overloading.
While what i'm writing here is not an answer per say, You must be exteremely careful when using __CALL as suggested here. The main reason is that you lose all control over visibility of functions, all functions are accessible which may or may not be what you want.
Other than __CALL though, What you want is called a proxy wrapper, Check out the answer by ocramius in this thread :
How to auto call function in php for every other function call
Notice that __CALL should always be avoided, if __CALL is the answer, the question is normally wrong.

invoking runtime created functions

I'm trying to dynamically create the base for a DB entity generalization for a project I'm working on. I basically want to dynamically create a set of standard methods and tools for the properties in any class that extends this. Much like the tools you get for free with Python/Django.
I got the idea from this guy: http://www.stubbles.org/archives/65-Extending-objects-with-new-methods-at-runtime.html
So I've implemented the __call function as described in the post above,
public function __call($method, $args) {
echo "<br>Calling ".$method;
if (isset($this->$method) === true) {
$func = $this->$method;
$func();
}
}
I have a function which gives me the objects public/protected properties through get_object_vars,
public function getJsonData() {
$var = get_object_vars($this);
foreach($var as &$value) {
if (is_object($value) && method_exists($value, 'getJsonData')) {
$value = $value->getJsonData;
}
}
return $var;
}
and now I want to create some methods for them:
public function __construct() {
foreach($this->getJsonData() as $name => $value) {
// Create standard getter
$methodName = "get".$name;
$me = $this;
$this->$methodName = function() use ($me, $methodName, $name) {
echo "<br>".$methodName." is called";
return $me->$name;
};
}
}
Thanks to Louis H. which pointed out the "use" keyword for this down below.
This basically creates an anonymous function on the fly. The function is callable, but it is no longer within the context of it's object. It produces a "Fatal error: Cannot access protected property"
Unfortunately I'm bound to PHP version 5.3, which rules out Closure::bind. The suggested solution in Lazy loading class methods in PHP will therefore not work here.
I'm rather stumped here... Any other suggestions?
Update
Edited for brevity.
Try it like this (you have to make the variables you'll need available to the method)
$this->$methodName = function() use ($this, $methodName, $name){
echo "<br>".$methodName." is called";
return $this->$$name;
};
You should have access to the object context through $this.
Instead of updating the original question above, I include the complete solution here for anybody struggling with the same issues:
First of all, since the closure cannot have real object access, I needed to include the actual value with the "use" declaration when creating the closure function (see original __construct function above):
$value =& $this->$name;
$this->$methodName = function() use ($me, $methodName, &$value) {
return $value;
};
Secondly the __call magic method did not just need to call the closure function, it needed also to return any output from it. So instead of just calling $func(), I return $func();
This did the trick! :-)

can I pass __construct parameters after a class has been instantiated into an object?

I have a similar code snippet like this
class Search
{
public function search($for, $regEx, $flag) //I would like this to be the constructor
{
// logic here
return $this;
}
}
Then I have another class that creates an object from it, later than tries to use the object.
class MyClass
{
public function start()
{
$this->search = new Search();
}
public function load()
{
$this->search($for, $regEx, $flag);
}
}
My question is, is it possible to create an object first THEN give it the parameters?
I know there are some way around this BUT I only ask because I want to use the object like this
$this->search($params);
// I have my methods chained, so I could use it in one line like
// $this->search($params)->hasResults();
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
The way I have it set up right now, I would need to use it like this
$this->search->search($params);
if ($this->search->hasResults()) {
echo 'found stuff';
} else {
echo 'didn't find anything';
}
I have a method called search() that does the logic, and I don't want to be redundant in my naming nor do I want to change the name of the method.
I know another way to keep the visual appeal sane I could pass a variable like so
$search = $this->search->search($params);
then
$search->hasResults();
At the same time I am trying to introduce myself to new OOP concepts and learn from them. Would this require passing things by reference? or setting up some type of magic method?
While the previous anwsers show that you can, I wouldn't use it, because it breaks the concept of encapsulation. A proper way to achieve what you want is the following
class Search
{
public function __constructor($for='', $regEx='', $flag='')
{
$this->Setup($for, $regEx, $flag);
}
public function Setup($for, $regEx, $flag)
{
//assign params
//clear last result search
//chain
return $this;
}
public function search()
{
// logic here
return $this;
}
}
In this way, you can reuse the object and have the params in the constructor, without breaking encapsulation.
Yes it is possible
See the below example
<?php
class a{
public $a = 5;
public function __construct($var){
$this->a = $var;
}
}
$delta = new a(10);
echo $delta->a."\n";
$delta->__construct(15);
echo $delta->a."\n";
Output will be:
10 15
Yep, you can.
class Example {
public $any;
function __counstruct($parameters,$some_text) {
$this->any=$some_text;
return $this->any;
}
}
You can call constructor:
$obj = new Example (true,'hello');
echo $obj->any;
$obj->__construct(true,'bye-bye');
echo $obj->any;
I was able to create the visual coding I wanted by using the __call() magic method like this
public function __call($name, $params)
{
$call = ucfirst($name);
$this->$name = new $call($params);
}
from there I could use this
$this->test->search($params);
$this->test->search->hasResults();
I of course now set the search() method to the class constructor

PHP add methods to Functions

Is it possible to add methods to functions?
For example:
<?
function func(){
;
}
//add method
func->test = function(){
;
}
func->test();
func();
I'm coming from a javascript background, and therefore I'm used to 'everything is an object'.
EDIT:
I was just explaining where the misconception may often come from for new phpers. I understand the above code doesn't work.
EDIT 2
Figured it out.
class myfunc_class{
function __invoke(){
//function body
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new myfunc_class;
$func->test = function(){
echo '<br>test<br>';
};
$func->test();
$func();
Even sexier :)
class func{
public $_function;
function __invoke(){
return call_user_func_array($this->_function,func_get_args());
}
function __construct($fun){
$this->_function = $fun;
}
function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$func = new func(function($value){
echo $value;
});
$func->method = function(){
echo '<br>test<br>';
};
$func('someValue');
$func->method();
No.
Not everything is an object in PHP. In fact the only thing that is an object is, well, an object. More specifically, and generally, an instantiation of a class.
Your code converted to PHP
// function_object.php
<?php
class FunctionObject {
public method func() {
// do stuff
}
}
?>
In other code you would use it like this:
<?php
// example.php in same folder as function_object.php
include 'function_object.php';
$FuncObj = new FunctionObject;
$FuncObj->func();
Also: read more about PHP & OOP
No, because an object is a different PHP language construct than a function. Functions do not have properties, but are instead simply execution instructions.
But, if func were instead a pre-defined class, then yes... with a bit of witchcraft, ignoring public outcry, foregoing readability and PHP coding standards, and by using closures with the __call() magic method...
class func
{
function __call($func, $args)
{
return call_user_func_array($this->$func, $args);
}
}
$obj = new func;
$obj->test = function($param1, $param2)
{
return $param1 + $param2;
};
echo $obj->test(1,1);
This won't work as you'd think without __call(), because by $obj->test(1,1), PHP thinks you're trying to call a non-existent method of func when out of object scope. But inside, being that the new "test" property is of a type: closure, the call_user_func_array() just sees the "test" property as just another function, so you can hide this bit of trickery from outside scope.
You would need your function func() to return an object, then you'd be able to do something like: func()->test();
But please note that your way of handling objects is not right in PHP and I suggest that you go read the OO documentations here.
In difference to javacript, in PHP not everything is an object. Therefore you need to differ between function and class.
If you want to create an object, you need to define the class first.
class myClass {
}
You can then add as many functions to the class as you need. But you need to define them first:
class myClass {
function test() {
echo "test!\n";
}
}
When everything is ready, you can bring it to life then:
$class = new myClass;
$class->test();
Checkout the manual for more.
You can't do what you're trying to do, but you can define functions inside of other functions.
This example outputs text:
function a() {
function b() { echo 'Hi'; }
}
a();
b();
Output: HiHi
This example outputs an error:
function a() {
function b() { echo 'Hi'; }
}
b();
Output: ERROR

Adding a custom function to an already instantiated object in PHP?

What's the best way to do something like this in PHP?:
$a = new CustomClass();
$a->customFunction = function() {
return 'Hello World';
}
echo $a->customFunction();
(The above code is not valid.)
Here is a simple and limited monkey-patch-like class for PHP. Methods added to the class instance must take the object reference ($this) as their first parameter, python-style.
Also, constructs like parent and self won't work.
OTOH, it allows you to patch any callback type into the class.
class Monkey {
private $_overload = "";
private static $_static = "";
public function addMethod($name, $callback) {
$this->_overload[$name] = $callback;
}
public function __call($name, $arguments) {
if(isset($this->_overload[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->_overload[$name], $arguments);
/* alternatively, if you prefer an argument array instead of an argument list (in the function)
return call_user_func($this->_overload[$name], $this, $arguments);
*/
} else {
throw new Exception("No registered method called ".__CLASS__."::".$name);
}
}
/* static method calling only works in PHP 5.3.0 and later */
public static function addStaticMethod($name, $callback) {
$this->_static[$name] = $callback;
}
public static function __callStatic($name, $arguments) {
if(isset($this->_static[$name])) {
return call_user_func($this->_static[$name], $arguments);
/* alternatively, if you prefer an argument list instead of an argument array (in the function)
return call_user_func_array($this->_static[$name], $arguments);
*/
} else {
throw new Exception("No registered method called ".__CLASS__."::".$name);
}
}
}
/* note, defined outside the class */
function patch($this, $arg1, $arg2) {
echo "Arguments $arg1 and $arg2\n";
}
$m = new Monkey();
$m->addMethod("patch", "patch");
$m->patch("one", "two");
/* any callback type works. This will apply `get_class_methods` to the $m object. Quite useless, but fun. */
$m->addMethod("inspect", "get_class_methods");
echo implode("\n", $m->inspect())."\n";
Unlike Javascript you can't assign functions to PHP classes after the fact (I assume you are coming from Javascript becuase you are using their anonymous functions).
Javascript has a Classless Prototypal system, where as PHP has a Classical Classing System. In PHP you have to define every class you are going to use, while in Javascript, you can create and change each object however you want.
In the words of Douglas Crockford: You can program in Javascript like it is a Classical System, but you can't program in a Classical System like it is Javascript. This means that a lot of the stuff you are able to do in Javascript, you can't do in PHP, without modifications.
I smell Adapter Pattern, or maybe even Decorator Pattern!

Categories