I have a question, I didn't clearly understand what Closures uses on OOP, but I did something like this:
<?php /** * */
class Xsample {
public static $name;
public static $address = array("Mandaluyong", "City");
public static function setName ($name) {
self::$name = $name;
}
public static function getName() {
echo self::$name;
}
public static function sub ($func) {
return call_user_func_array($func, self::$address);
}
}
Xsample::setName("Eric");
Xsample::sub(function ($address) {
echo $address;
});
?>
and it echo "Mandaluyong".
I'm expecting that it'll return an array from Xsample::$address but it didn't. Could someone please explain this to me?
call_user_func_array passes the 2nd argument's elements as paramters to the function being called. so if your function had another parameter it will work.
Xsample::sub(function ($address, $address2) {
echo $address;
echo $address2;
});
Related
I like PHP, but I miss some of the constructs from other languages that although don't do anything for performance, make the code look cleaner and possibly more maintainable. I'm thinking of Visual Basic days and the "with" statement.
So ideally in PHP we could do this:
with($myWellDescribedInstance) {
->property1="string";
->property2=1;
->property3=2;
->myMethod();
}
Instead of
$myWellDescribedInstance->property1="string";
$myWellDescribedInstance->property2=1;
$myWellDescribedInstance->property3=2;
$myWellDescribedInstance->myMethod();
Is there anything like this in PHP?
You can implement a fluent interface on any class just by having a function return $this.
This is mostly used for setters, but of course it works for any method for which you would normally not have a return value.
For example:
class Person
{
protected $name = '';
protected $surname = '';
protected $email = '';
public function getName()
{
return $this->name;
}
public function getSurname()
{
return $this->surname;
}
public function getEmail()
{
return $this->email;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function setSurname($surname)
{
$this->surname = $surname;
return $this;
}
public function setEmail($email)
{
$this->email = $email;
return $this;
}
}
Usage:
$person = new Person;
$person->setName('John')
->setSurname('Doe')
->setEmail('johndoe#email.com');
Of course, calling the method (for example) setName or withName would be entirely up to you.
Another idea might be to have both a setName method (which doesn't return anything) and a withName method (which returns $this), but that might be a bit of an overkill.
If you use "setters" instead of direct property access you can chain methods.
class A {
private $a;
private $b;
public function setA($a)
{
$this->a = $a;
return $this;
}
public function setB($b)
{
$this->b = $b;
return $this;
}
public function doSomething()
{}
}
$a = new A();
$a->setA('a')
->setB('b')
->doSomething();
I have a class and two functions inside it as follows:
class MyClassName
{
protected function myFunction1()
{
// some code here
return $something;
}
public function myFunction2()
{
// some code here
return $somethingElse;
}
}
What I need to do is define a variable in myFunction1() and then use it in myFunction2(). What is the best practice to do that?
class MyClassName
{
public $var = 0;
protected function myFunction1()
{
// some code here
$this->var = ...;
return $something;
}
public function myFunction2()
{
// some code here
echo $this->var;
return $somethingElse;
}
}
Actually vars should be defined out of the function and then set a value. Then can be modified over all the script, by doing this->var
Make it a class property
class MyClassName
{
private $property;
public function __construct() {
$this->myFunction1();
}
protected function myFunction1()
{
// some code here
$this->property = 'an apple';
}
public function myFunction2()
{
// some code here
return $this->property;
}
}
Now test it:
$my_class = new MyClassName();
$something = $my_class->myFunction2();
echo $something;
I have:
function sayName($param)
{
echo $param();
}
class Robin
{
public static $name = "Robin Webber";
public static function bearName()
{
echo static::$name;
}
}
sayName(array("Robin", 'bearName'));
This code is a little counter intuitive to me.
How exactly does passing an array to sayNam() call the static method of the class Robin?
Any references to PHP documentation on this behavior for examination would be helpful.
Do it:
function sayName(array $params)
{
$class = array_shift($params);
$method = array_shift($params);
call_user_func_array($class.'::'.$method,array());
// or call_user_func($class.'::'.$method);
}
class Robin
{
public static $name = "Robin Webber";
public static function bearName()
{
echo static::$name;
}
}
sayName(array("Robin", 'bearName'));
//Robin Webber
See more call_user_func and call_user_func_array.
I need to implement the following pattern in php:
class EventSubscriber
{
private $userCode;
public function __construct(&$userCode) { $this->userCode = &$userCode; }
public function Subscribe($eventHandler) { $userCode[] = $eventHandler; }
}
class Event
{
private $subscriber;
private $userCode = array();
public function __construct()
{
$this->subscriber = new Subscriber($this->userCode)
}
public function Subscriber() { return $this->subscriber; }
public function Fire()
{
foreach ($this->userCode as $eventHandler)
{
/* Here i need to execute $eventHandler */
}
}
}
class Button
{
private $eventClick;
public function __construct() { $this->eventClick = new Event(); }
public function EventClick() { return $this->eventClick->Subscriber(); }
public function Render()
{
if (/* Button was clicked */) $this->eventClick->Fire();
return '<input type="button" />';
}
}
class Page
{
private $button;
// THIS IS PRIVATE CLASS MEMBER !!!
private function ButtonClickedHandler($sender, $eventArgs)
{
echo "button was clicked";
}
public function __construct()
{
$this->button = new Button();
$this->button->EventClick()->Subscribe(array($this, 'ButtonClickedHandler'));
}
...
}
what is the correct way to do so.
P.S.
I was using call_user_func for that purpose and believe it or not it was able to call private class members, but after few weeks of development i've found that it stopped working. Was it a bug in my code or was it some something else that made me think that 'call_user_func' is able call private class functions, I don't know, but now I'm looking for a simple, fast and elegant method of safely calling one's private class member from other class. I'm looking to closures right now, but have problems with '$this' inside closure...
Callbacks in PHP aren't like callbacks in most other languages. Typical languages represent callbacks as pointers, whereas PHP represents them as strings. There's no "magic" between the string or array() syntax and the call. call_user_func(array($obj, 'str')) is syntactically the same as $obj->str(). If str is private, the call will fail.
You should simply make your event handler public. This has valid semantic meaning, i.e., "intended to be called from outside my class."
This implementation choice has other interesting side effects, for example:
class Food {
static function getCallback() {
return 'self::func';
}
static function func() {}
static function go() {
call_user_func(self::getCallback()); // Calls the intended function
}
}
class Barf {
static function go() {
call_user_func(Food::getCallback()); // 'self' is interpreted as 'Barf', so:
} // Error -- no function 'func' in 'Barf'
}
Anyway, if someone's interested, I've found the only possible solution via ReflectionMethod. Using this method with Php 5.3.2 gives performance penalty and is 2.3 times slower than calling class member directly, and only 1.3 times slower than call_user_func method. So in my case it is absolutely acceptable. Here's the code if someone interested:
class EventArgs {
}
class EventEraser {
private $eventIndex;
private $eventErased;
private $eventHandlers;
public function __construct($eventIndex, array &$eventHandlers) {
$this->eventIndex = $eventIndex;
$this->eventHandlers = &$eventHandlers;
}
public function RemoveEventHandler() {
if (!$this->eventErased) {
unset($this->eventHandlers[$this->eventIndex]);
$this->eventErased = true;
}
}
}
class EventSubscriber {
private $eventIndex;
private $eventHandlers;
public function __construct(array &$eventHandlers) {
$this->eventIndex = 0;
$this->eventHandlers = &$eventHandlers;
}
public function AddEventHandler(EventHandler $eventHandler) {
$this->eventHandlers[$this->eventIndex++] = $eventHandler;
}
public function AddRemovableEventHandler(EventHandler $eventHandler) {
$this->eventHandlers[$this->eventIndex] = $eventHandler;
$result = new EventEraser($this->eventIndex++, $this->eventHandlers);
return $result;
}
}
class EventHandler {
private $owner;
private $method;
public function __construct($owner, $methodName) {
$this->owner = $owner;
$this->method = new \ReflectionMethod($owner, $methodName);
$this->method->setAccessible(true);
}
public function Invoke($sender, $eventArgs) {
$this->method->invoke($this->owner, $sender, $eventArgs);
}
}
class Event {
private $unlocked = true;
private $eventReceiver;
private $eventHandlers;
private $recursionAllowed = true;
public function __construct() {
$this->eventHandlers = array();
}
public function GetUnlocked() {
return $this->unlocked;
}
public function SetUnlocked($value) {
$this->unlocked = $value;
}
public function FireEventHandlers($sender, $eventArgs) {
if ($this->unlocked) {
//защита от рекурсии
if ($this->recursionAllowed) {
$this->recursionAllowed = false;
foreach ($this->eventHandlers as $eventHandler) {
$eventHandler->Invoke($sender, $eventArgs);
}
$this->recursionAllowed = true;
}
}
}
public function Subscriber() {
if ($this->eventReceiver == null) {
$this->eventReceiver = new EventSubscriber($this->eventHandlers);
}
return $this->eventReceiver;
}
}
As time passes, there are new ways of achieving this.
Currently PSR-14 is drafted to handle this use case.
So you might find any of these interesting:
https://packagist.org/?query=psr-14
i'm trying to play with php5.3 and closure.
I see here (Listing 7. Closure inside an object : http://www.ibm.com/developerworks/opensource/library/os-php-5.3new2/index.html) that it's possible to use $this in the callback function, but it's not. So I try to give $this as use variable :
$self = $this;
$foo = function() use($self) { //do something with $self }
So to use the same example :
class Dog
{
private $_name;
protected $_color;
public function __construct($name, $color)
{
$this->_name = $name;
$this->_color = $color;
}
public function greet($greeting)
{
$self = $this;
return function() use ($greeting, $self) {
echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
};
}
}
$dog = new Dog("Rover","red");
$dog->greet("Hello");
Output:
Hello, I am a red dog named Rover.
First of all this example does not print the string but return the function, but that's not my problem.
Secondly I can't access to private or protected, because the callback function is a global function and not in the context from the Dog object. Tha't my problem. It's the same as :
function greet($greeting, $object) {
echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
}
And I want :
public function greet($greeting) {
echo "$greeting, I am a {$self->_color} dog named {$self->_name}.";
}
Which is from Dog and not global.
Well, the whole reason that you can't use $this, is because the closure is an object in the background (the Closure class).
There are two ways around this. First, is add the __invoke method (What's called if you call $obj())..
class Dog {
public function __invoke($method) {
$args = func_get_args();
array_shift($args); //get rid of the method name
if (is_callable(array($this, $method))) {
return call_user_func_array(array($this, $method), $args);
} else {
throw new BadMethodCallException('Unknown method: '.$method);
}
}
public function greet($greeting) {
$self = $this;
return function() use ($greeting, $self) {
$self('do_greet', $greeting);
};
}
protected function do_greet($greeting) {
echo "$greeting, I am a {$this->_color} dog named {$this->_name}.";
}
}
If you want the closure to not change if you modify the host object, you can just change the return function to something like:
public function greet($greeting) {
$self = (clone) $this;
return function() use ($greeting, $self) {
$self('do_greet', $greeting);
};
}
The other option, is to provide a generic getter:
class Dog {
public function __get($name) {
return isset($this->$name) ? $this->$name : null;
}
}
For more information, see: http://www.php.net/manual/en/language.oop5.magic.php
As of PHP 5.4.0 Alpha1, you can access $this from within the context of an object instance:
<?php
class Dog
{
private $_name;
protected $_color;
public function __construct($name, $color)
{
$this->_name = $name;
$this->_color = $color;
}
public function greet($greeting)
{
$func = function() use ($greeting) {
echo "$greeting, I am a {$this->_color} dog named {$this->_name}.";
};
$func();
}
}
$dog = new Dog("Rover","red");
$dog->greet("Hello");
You can also do this:
$dog = new Dog("Rover", "red");
$getname = Closure::bind($dog, function() { return $this->_name; });
echo $getname(); // Rover
As you can see, it's possible to easily mess with private data... so be careful.
Well it makes sense that you cannot access private and protected fields of an object. And by explicitly passing $self to your function, it is treated just as a normal object.
You should create getters in order to access these values , i.e. :
class Dog
{
private $_name;
protected $_color;
public function __construct($name, $color)
{
$this->_name = $name;
$this->_color = $color;
}
public function getName() {
return $this->_name;
}
public function getColor() {
return $this->_color;
}
public function greet($greeting)
{
$self = $this;
return function() use ($greeting, $self) {
echo "$greeting, I am a {$self->getColor()} dog named {$self->getName()}.";
};
}
}
You should create getter (and setters) anyway, for matter of encapsulation.
Another note: The article you link to was published before the final version of PHP 5.3 was released. Maybe this implicit object passing was removed.
I use this create_closure() in my work to seperate callbacks into Classes:
<?php
function create_closure($fun, $args, $uses)
{$params=explode(',', trim($args.','.$uses, ','));
$str_params='';
foreach ($params as $v)
{$v=trim($v, ' &$');
$str_params.='\''.$v.'\'=>&$'.$v.', ';
}
return "return function({$args}) use ({$uses}) {{$fun}(array({$str_params}));};";
}
?>
example:
<?php
$loop->addPeriodicTimer(1, eval(create_closure('pop_message', '$timer', '$cache_key, $n, &$response, &$redis_client')));
function pop_message($params)
{extract($params, EXTR_REFS);
$redis_client->ZRANGE($cache_key, 0, $n)
->then(//normal
function($data) use ($cache_key, $n, &$timer, &$response, &$redis_client)
{//...
},
//exception
function ($e) use (&$timer, &$response, &$redis_client)
{//...
}
);
}
?>