You can always call protected members using the __call() method - similar to how you hack around this in Ruby using send.
<?php
class Fun
{
protected function debug($message)
{
echo "DEBUG: $message\n";
}
public function yield_something($callback)
{
return $callback("Soemthing!!");
}
public function having_fun()
{
$self =& $this;
return $this->yield_something(function($data) use (&$self)
{
$self->debug("Doing stuff to the data");
// do something with $data
$self->debug("Finished doing stuff with the data.");
});
}
// Ah-Ha!
public function __call($method, $args = array())
{
if(is_callable(array($this, $method)))
return call_user_func_array(array($this, $method), $args);
}
}
$fun = new Fun();
echo $fun->having_fun();
?>
Anonim işlevler
Anonim işlevler isim belirtmeksizin oluşturulabilen işlevlerdir. Çoğunlukla geriçağırım işlevi olarak işlev değiştirgelerinde kullanılırsa da kullanımı bununla sınırlı değildir.
Örnek 1 - Anonim işlev örneği
<?php
echo preg_replace_callback('~-([a-z])~',
function ($match) {
return strtoupper($match[1]);
},
'hello-world');
// Çıktısı: helloWorld
?>
Anonim işlevler birer değişken değeri olarak da bildirilebilir. Bu durumda PHP, işlevi özdevinimli olarak sınıfının nesnel bir örneği haline getirir. Bir anonim işlev, bir değişkene sıradan bir deyim gibi, bir noktalı virgül ile biten bir işlev olarak atanabilir:
Örnek 2 - Değişkene anonim işlev atama örneği
<?php
$greet = function($isim)
{
printf("Merhaba %s\r\n", $isim);
};
$greet('Dünya');
$greet('PHP');
?>
Anonim işlevler değişkenleri üst etki alanındın miras alabilirler. Böyle değişkenler işlevin baş tarafında bildirilebilir. Üst etki alanından miras alınan değişkenler küresel değişkenler gibi ele alınmazlar. Küresel değişkenler, işlevin çalıştığı etki alanında tanımlı değişkenlerdir. Anonim işlevin üst etki alanı ise içinde bildirildiği işlevin etki alanıdır (Anonim işlevin bildirildiği ekti alanı ile çağrıldığı etki alanı aynı olmak zorunda değildir). Aşağıdaki örneğe bakalım:
Örnek 3 - Anonim işlevler ve etki alanı
<?php
// Ürünleri eklemek üzere bir Sepet oluşturalım.
// Eklenen ürünlerin toplam fiyatını döndürmek
// üzere bir geriçağırım işlevi kullanalım.
class Sepet
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $ürünler = Array();
public static function ekle($ürün, $miktar)
{
$this->ürünler[$ürün] = $miktar;
}
public static function miktarıGetir($ürün)
{
return isset($this->ürünler[$ürün]) ? $this->ürünler[$ürün] : FALSE;
}
public function Toplam($kdv)
{
$toplam = 0.00;
$işlev =
function ($miktar, $ürün) use ($kdv, &$toplam)
{
$birimFiyat = constant(__CLASS__ . "::FiYAT_" .
strtoupper($ürün));
$toplam += ($birimFiyat * $miktar) * ($kdv + 1.0);
};
array_walk($this->ürünler, $işlev);
return round($toplam, 2);;
}
}
$sepetim = new Sepet;
// Sepete birşeyler ekleyelim
$sepetim->ekle('Peynir', 1);
$sepetim->ekle('Süt', 3);
$sepetim->ekle('Yumurta', 6);
// %5 KDV ile toplamı döndürelim
print $sepetim->Toplam(0.05) . "\n";
// sonuç: is 54.29
?>
Anonim işlevler dahili olarak Closure sınıfı ile gerçeklenmektedir.
Bilginize: Anonim işlevler PHP 5.3.0'dan beri kullanılabilmektedir.
Bilginize: func_num_args(), func_get_args() ve func_get_args() işlevini bir anonim işlev içinde kullanmak mümkündür.
Anonim işlevler
25-Nov-2009 06:20
28-Oct-2009 04:40
To recursively call a closure, use this code.
<?php
$recursive = function () use (&$recursive){
// The function is now available as $recursive
}
?>
This DOES NOT WORK
<?php
$recursive = function () use ($recursive){
// The function is now available as $recursive
}
?>
13-Oct-2009 12:22
be aware of Fatal error: Using $this when not in object context when using in closures
http://wiki.php.net/rfc/closures/removal-of-this
07-Oct-2009 02:41
The text above the third example tries to explain that anonymous functions can inherit variables from the parent scope, but fails to properly explain how this is done: namely using the "use" keyword in the function definition.
The following page has a much more detailed explanation of closures in PHP 5.3:
http://wiki.php.net/rfc/closures
03-Oct-2009 05:06
Very easy way to get the netstat (windows)... yes, this could be a function, but as an example, here it is in closure form...
<?php
$netstat = function($return = null, $precision = 2) {
// supplement function
$_convert = function ($bytes) use ($precision) {
$i = 0; $iec = array('b', 'kb', 'mb', 'gb', 'tb', 'pb', 'eb', 'zb', 'yb');
while (($bytes / 1024) > 1): $bytes = $bytes / 1024; $i++; endwhile;
return round(substr($bytes, 0, strpos($bytes, '.') + 4), $precision) . ' ' . strtoupper($iec[$i]);
};
foreach (explode("\n", `netstat -e`) as $d) {
if (preg_match('/^Bytes([\s].+)([0-9])([\s].+)([0-9])/', $d, $m)) {
switch ($return) {
case 'sent': return $_convert(trim($m[1].$m[2])); break;
case 'recv': return $_convert(trim($m[3].$m[4])); break;
default: return array('sent' => $_convert(trim($m[1].$m[2])),
'recv' => $_convert(trim($m[3].$m[4]))); break;
}
}
}
};
?>
09-Sep-2009 10:52
<?php
/**
* Using closures to dynamically extend objects
*
*/
class ClosureTest{
public $member = 'test';
protected $protectedMember = 'protectedtest';
public function __call($method, $args)
{
return call_user_func_array( $this->$method, $args);
}
}
$object = new ClosureTest();
$object->closure = function() use ($object){
return $object->member;
};
echo $object->closure();
//Output: 'test'
/**
* This won't work, you can not access protected/private members, which is fine.
*/
$object->closureAccessProtected = function() use ($object){
return $object->protectedMember;
};
$object->closureAccessProtected();
?>
10-Aug-2009 09:34
Ulderico had it almost right. To avoid confusing the interpreter, when using a simple closure stored in a $variable, you must invoke the nameless function using the function syntax.
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld( );
?>
Note the empty actual-parameter list in the "echo". NOW IT WORKS.
03-Aug-2009 09:50
If you want to check whether you're dealing with a closure specifically and not a string or array callback you can do this:
<?php
$isAClosure = is_callable($thing) && is_object($thing);
?>
29-Jul-2009 10:51
Unfortunately, you can't get a pointer to a function, the only function pointers are ones which use anonymous functions as they're created.
This wont work:
<?php
$info = phpinfo;
$info();
//or
function foo() {
echo 'bar';
}
$foo = foo;
$foo();
?>
Because of the behavior of $foo(), it will assume $foo is a string, and try to run the function with the name stored in the string.
14-Jul-2009 02:43
Perhaps you'll find yourself wanting doing a wicked thing like:
<?php
$helloworld = function(){
return "each hello world is different... ".date("His");
};
echo $helloworld;
?>
which throws:
Catchable fatal error: Object of class String could not be converted to string
OK... Here's the way of doing this.
<?php
class Helloworld{
function __toString(){
return("each hello world is different...".date("His"));
}
}
$helloworld = new Helloworld();
echo $helloworld;
sleep(5);
echo $helloworld;
?>
30-Jun-2009 12:49
Example using uasort.
<?php
// Usual method.
function cmp($a, $b) {
return($a > $b);
}
uasort($array, 'cmp');
// New
uasort($array, function($a, $b) {
return($a > $b);
});
?>
19-Jun-2009 09:55
When using anonymous functions as properties in Classes, note that there are three name scopes: one for constants, one for properties and one for methods. That means, you can use the same name for a constant, for a property and for a method at a time.
Since a property can be also an anonymous function as of PHP 5.3.0, an oddity arises when they share the same name, not meaning that there would be any conflict.
Consider the following example:
<?php
class MyClass {
const member = 1;
public $member;
public function member () {
return "method 'member'";
}
public function __construct () {
$this->member = function () {
return "anonymous function 'member'";
};
}
}
header("Content-Type: text/plain");
$myObj = new MyClass();
var_dump(MyClass::member); // int(1)
var_dump($myObj->member); // object(Closure)#2 (0) {}
var_dump($myObj->member()); // string(15) "method 'member'"
$myMember = $myObj->member;
var_dump($myMember()); // string(27) "anonymous function 'member'"
?>
That means, regular method invocations work like expected and like before. The anonymous function instead, must be retrieved into a variable first (just like a property) and can only then be invoked.
Best regards,
