Sınıf üyeleri olarak Closures?

6 Cevap php

Ben kapanışları üzerinden işlevselliğini artırmanın jQuery / Javascript 'nin yolu bir zevk almış. PHP 5.3 benzer bir şey yapmak mümkün mü?

class Foo
{
    public $bar;
}

$foo = new Foo;
$foo->bar = function($baz) { echo strtoupper($baz); };
$foo->bar('lorem ipsum dolor sit amet');
// LOREM IPSUM DOLOR SIT AMET

[Değiştir] karışık 'o' ve benim soru 'olduğu'. heh.

UPDATE

Ben 5.3a3 indirilen ve çalışır!

class Foo
{
    protected $bar;
    public $baz;

    public function __construct($closure)
    {
        $this->bar = $closure;
    }

    public function __call($method, $args)
    {
        $closure = $this->$method;
        call_user_func_array($closure, $args);
    }

}

$foo = new Foo(function($name) { echo "Hello, $name!\n"; });
$foo->bar('Mon'); 
// Hello, Mon!
$foo->baz = function($s) { echo strtoupper($s); };
$foo->baz('the quick brown fox jumps over the lazy dog');
// THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG

6 Cevap

PHP 5.3 Eğer kod örneğini uygulamak için izin verecek lambda fonksiyonları ve kapanışları oluşturulmasını sağlayacaktır. Kimden PHP RFC:

function & (parameters) use (lexical vars) { body }

Fonksiyonu referans olarak döndürülür ve bir geri olarak kabul edilebilir. Örneğin, bir işlev oluştururken:

$lambda = function () { echo "Hello World!\n"; };

Bir geri olarak bir lambda fonksiyonu Passing:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

Kapaklar da yerel kapsam değişkenleri almak için izin:

$map = function ($text) use ($search, $replacement) {
    if (strpos ($text, $search) > 50) {
       return str_replace ($search, $replacement, $text);
    } else {
        return $text;
    }
};

$ Arama ve $ yerine hem kapatılması dışında ilan ve $ metin fonksiyonu parametresi nerede.

Sen yeniden rota varolmayan yöntem çağrıları için __call yönteminin yararlanabilirsiniz. Eğer sinek yöntemlerini eklemek / kaldırmak böylece sınıf için bir kayıt ekleyin. Dış işlev için çağırma ilk parametre fonksiyonu bağlı olan nesne olmasıdır.

clas Foo {

    private $registry;

    public function __call($alias, $args) {
        if (array_key_exists($alias, $this->registry)) {
            // prepend list of parameters with $this object
            array_unshift($args, $this);
            return call_user_func_array($this->registry[$alias], $args)
        }
    }

    public function register($method, $alias = null) {
        $alias or $alias = $method; // use original method name if no alias
        $this->registry[$alias] = $method;
    }

    public function unregister($alias) {
        unset($this->registry[$alias]);
    }

}

Klonlanmış nesneleri dizisini döndürür fonksiyonunu clone_object düşünün. İlk parametre klonlanacak amacı ve ikinci klon sayısıdır.

function clone_object($foo, $n) {
    $a = array();
    while ($n--) {
        $a[] = clone $foo;
    }
    return $a;
}

Şimdi, clone_object Foo sınıfa yöntemi enjekte ve bu bir takma ad verebilirsiniz bu şekilde bar:

$f = new Foo();
$f->register('clone_object', 'bar');
$f->bar(5); // this will return array of 5 cloned objects

Son satırı arama yöntemi olarak bar fonksiyonuna yönlendirmeyi neden olacaktır clone_object. Çağırma parametreler listesine içine parametre $this eklemek, böylece (5) ($this, 5) olarak değiştirildi olacağını akla.

Ihtar harici fonksiyonlar Özel / korumalı özellikleri ve yöntemleri üzerinde çalışmıyor olabilir.

Sadece son bir kelime, size anında nesneleri değişmez bir çözüm düşünüp eğer, muhtemelen bunu kullanmalısınız. Yukarıdaki siyah bir sihirbazlık ve çok dikkatli kullanılmalıdır.

PHP can yoluyla create_function(). Sözdizimi neredeyse tamamen yararsız render olsa cruciating edilir.

Bu PHP5.3+ / closures and lambda's! için desteği vardır oluyor gibi görünüyor

Bununla birlikte, aynı zamanda gelen RFC

Lambda fonksiyonları / kapama çalışma zamanında dinamik olarak ek yöntemlerle sınıflar uzanan bir yol değildir. __ Semantik arama zaten mevcut dahil olmak üzere bu yapmak için çeşitli diğer olasılıkları vardır.

Uygun anonim fonksiyonlar / kapaklar bir süre için yaygın olarak kullanılabilir olmayacak ki, PHP 5.3 'te sadece mevcut - some useful information. Ben ne istediğinizi yapmak gerçekten mümkün olduğunu sanmıyorum.

Sen create_function() bir ölçüde kullanabilirsiniz:

$func = create_function('$baz', ' echo strtoupper($baz); ');
$func("hello");

Beklediğiniz gibi Ancak şu çalışmıyor:

$foo = new Foo;
$foo->bar = create_function('$baz', ' echo strtoupper($baz); ');
$foo->bar('lorem ipsum dolor sit amet');

Yerine yapmanız gerekir:

call_user_func($foo->bar, 'lorem ipsum dolor sit amet');

Kapsamı bir yöntem olarak aynı olmaz çünkü Ayrıca oluşturduğunuz işlev içinde $this kullanamazsınız.

Edit

Benimkini yazarken onun da düzenlenebilir olarak ben yanlışlıkla Martijn cevabı bazı çoğaltılamaz. Ben bütünlüğü uğruna sağlam benim cevabım terk edecek

Another edit

Sen belki de böyle bir şey yapabilir

class Foo
{
    public $bar;

    protected $anonFuncs = array();

    public function create_method($name, $params, $code) {
        if (strlen($params)) $params .= ',';
        $params .= '$self';
        $this->anonFuncs[$name] = create_function($params, $code);
    }

    public function __call($name, $args) {
        if (!isset($this->anonFuncs[$name])) {
            trigger_error("No method $name", E_USER_ERROR);
        }

        $args[] = $this;

        return call_user_func_array($this->anonFuncs[$name], $args);
    }
}

$foo = new Foo;
$foo->create_method('bar', '$baz', ' echo strtoupper($baz) . get_class($self); ');
$foo->bar('lorem ipsum dolor sit amet');

Yaratmak işlevini kullanma gibi bir şey yapabilirsiniz:

$Dynamic->lambda = create_function('$var', 'return $var." world."; ');
$classic = $Dynamic->lambda("hello"); // classic would contain "hello world."

Sınıf kodu gibi bir şey içerecektir:

public function __set($methodname, $function)
{
    $this->methods[$methodname] = $function;
}

public function __get($methodname)
{
    return $this->methods[$methodname];
}

public function __call($method, $args)
{
   $funct = $this->{$method};
   //$args[] = $this; --to add the current object as a parameter option
   return call_user_func_array($funct, $args);
}

Not: Eğer temelde bu sadece genel ad alanında olduğu create_function bir nesne arayüzü kullanıyor gibi, oluşturmak işlevi nesne kapsamını ($this değişkeni) kullanmak mümkün olmayacaktır. Kolayca parametre listesine nesnesinin bir örneğini ekler ve sınıfa çekin, ama sonra tekrar sadece sınıf içeri çekti kamu yöntemlerine erişim olurdu olabilir ancak

PHP5.4 sunulduğundan beri hatta daha fazlasını yapabilirsiniz:

  1. Dynamically nesneler için yöntemleri eklemek
  2. $this Bu yöntemlerin içinde kullanın
  3. Diğerinden Inherit bir dinamik nesne

Temel fikir burada yapılır: https://github.com/ptrofimov/jslikeobject