PHP 5.4 - 'closure $this support'
This was already planned for PHP 5.3, but
For PHP 5.3 $this support for Closures was removed because no consensus could be reached how to implement it in a sane fashion. This RFC describes the possible roads that can be taken to implement it in the next PHP version.
It indeed means you can refer to the object instance (live demo)
<?php
class A {
private $value = 1;
public function getClosure()
{
return function() { return $this->value; };
}
}
$a = new A;
$fn = $a->getClosure();
echo $fn(); // 1
For a discussion, see the PHP Wiki
- Closures: Object extension
and for historic interest:
- closures (rfc)
- removal-of-this (rfc:closures)
How to bind $this to a closure that is passed as a method parameter in PHP 5.4?
I actually didn't understand why using the bindTo
method didn't work in this case, but I could get it to work using Closure::bind
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$bound = Closure::bind($callback, $this);
$bound();
}
Edit
Aparently the bindTo
method has the same behavior, so you should reassign its return value to $callback
. For example:
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$callback = $callback->bindTo($this);
$callback();
}
Can't access $this on PHP Closure passed to an object method
To avoid the use of $p
, you can pass $this
in the call of the closure. But you can't use $this
in an anonymous function.
$this->__data = array_merge($this->__data, $map($this));
Then,
->setAutoData(function ($object) {
$array = explode(' ', $object->getData('full_name'));
return [
'first_name' => array_shift($array),
];
})
Note that array_shift
requires a reference. You should create a variable for that.
Code:
class Person
{
private $__data = [];
public function setData($key, $value)
{
$this->__data[$key] = $value;
return $this;
}
public function setAutoData($map)
{
$this->__data = array_merge($this->__data, $map($this));
return $this;
}
public function getData($key)
{
return $this->__data[$key];
}
}
print_r(
(new Person())
->setData('full_name', 'Valerie Maddison Bricks')
->setAutoData(function ($object) {
$array = explode(' ', $object->getData('full_name'));
return [
'first_name' => array_shift($array),
];
})
);
Output:
Person Object
(
[__data:Person:private] => Array
(
[full_name] => Valerie Maddison Bricks
[first_name] => Valerie
)
)
Why can I not use $this as a lexical variable in PHP 5.5.4?
So it seems $this can be used simply if it isn't specified via the "use" keyword.
The following echoes 'bar':
class Foo
{
private $foo = 'bar';
public function bar()
{
return function()
{
echo $this->foo;
};
}
}
$bar = (new Foo)->bar();
$bar();
This was reported in the php-internals mailing list and is apparently overhang from 5.3's lack of support for this functionality:
http://marc.info/?l=php-internals&m=132592886711725
Scope Resolution: objects with closure calls
Its right on the man page for php anonymous functions:
Changelog
Version Description
5.4.0 $this can be used in anonymous functions.
5.3.0 Anonymous functions become available.
http://php.net/manual/en/functions.anonymous.php
Also
PHP 5.4 - 'closure $this support'
Is there a workaround for $this within a closure in PHP 5.3?
If info method is public you can do:
//...
public function fire()
{
$self = $this;
$self->info('Starting chunk');
Item::chunk(1000, function($items) use ($self)
{
foreach ($items as $item)
{
$self->info($item->img);
}
}
);
}
//...
If info is private you can't and you need to upgrade to php 5.4, because in PHP 5.3 the context in the closure is not the same of the object context.
Object context - Using $this in PHP 5.3 vs PHP 5.4
Correct. Views are rendered in a closure which is designed to act like a sandbox.
$this in a view should not work, but it looks like in PHP 5.4 it will pick up an object higher in the callstack, as it gives you Request, and not View or your controller. Which already indicates it's not reliable to use, as what $this represents will depend on the callstack.
Even if you don't use a templating engine, it is considered bad practice to use "logic" in your views, other than the logic needed to generate the HTML. Pass the data required to the view, either from the controller, or use a Viewmodel to prep the data.
Related Topics
Pass Arraylist Bean from Android to Webservice PHP
PHP Include Best Practices Question
PHP Regular Expression for Strong Password Validation
How to Convert Word Smart Quotes and Em Dashes in a String
PHP _Php_Incomplete_Class Object with My $_Session Data
Getting Pear to Work on Xampp (Apache/MySQL Stack on Windows)
Why Is It Whenever I Use Scandir() I Receive Periods at the Beginning of the Array
How to Get All Captures of Subgroup Matches with Preg_Match_All()
Which Tokens Can Be Parameterized in Pdo Prepared Statements
Decode a Quoted Printable Message in PHP
Prevent Direct Url Access to PHP File
Xmlparseentityref: No Name' Warnings While Loading Xml into a PHP File
Woocommerce:Add Custom Metabox to Admin Order Page
How to Remove the Url Protocol and Slash from User Input in PHP