Qualche difficoltà nel capire nel php l'implementazione della closure

In javascript tutto è più semplice. Ora sto usando/imparando Phalcon e il secondo esempio/tutorial è strambo un bel po' (INVO).

Definisce una class Services, derivata da \Base\Services, a sua volta derivata da \Phalcon\Di\FactoryDefault.

In \Base\Services è definito un metodo, bindServices(), che cicla sui metodi definiti per la classe stessa, controllando che abbiano almeno 4 lettere, e che le prime 4 siano 'init'. In caso affermativo fa ... meglio incollare il codice:

    protected function bindServices()
    {
        $reflection = new \ReflectionObject($this);
        $methods = $reflection->getMethods();
        
        foreach ($methods as $method) {

            if ((strlen($method->name) > 10) && (strpos($method->name, 'initShared') === 0)) {
                $this->set(lcfirst(substr($method->name, 10)), $method->getClosure($this));
                continue;
            }
            
            if ((strlen($method->name) > 4) && (strpos($method->name, 'init') === 0)) {
                $this->set(lcfirst(substr($method->name, 4)), $method->getClosure($this));
            }

        }
        
    }

 

strano no? Poi in \Services vengono definiti i vari metodi initDb, initUrl, ... e così via.

Elegante? Forse, ma oscuro per me, io non voglio scrivere così.

Innanzi tutto voglio ereditare direttamente da \Phalcon\Di\FactoryDefault, che sia chiaro. Poi se aggiungo una qualche inizializzazione che sia esplicita e non implicita nel nome, perché altrimenti mi sa di magico e la magia la si maneggia male, secondo me.

Ecco, va a finire che il mio bindServices() è:

    private function bindServices()
    {
        $reflection = new \ReflectionObject($this);
	$this->set('url', $reflection->getMethod('initUrl')->getClosure($this));
        
    }

 

avrei la tentazione di ciclare, ma forse così:

    private function bindServices()
    {
        $reflection = new \ReflectionObject($this);
	$services = ['url' => 'initUrl','db'=>'initDb'];
	foreach($services as $service => $method) {
		$this->set($service, $reflection->getMethod($method)->getClosure($this));
	}
    }

 

almeno definizione e uso sono vicini, e si capisce, e si capisce anche come si usa ReflectionObject (ed esiste il metodo getMethod(), senza 's' finale!).

A beh, riguardo al riuso, potrei anche capirlo, ma allora basterebbe definire $services come una proprietà dell'oggetto che eredita

 

    protected $services = [];
    protected function bindServices()
    {
        $reflection = new \ReflectionObject($this);
	foreach($this->services as $service => $method) {
		$this->set($service, $reflection->getMethod($method)->getClosure($this));
	}
    }

(ma cosa vuoi riusare poi?) comunque trovo una pessima idea andare a fare magheggi con i nomi di metodi su di una classe che eredito da un framework, il quale potrebbe introdurre altri metodi in futuro e costringermi ad aggiungere eccezioni (al magheggio). Vero è che se aggiungeressero initUrl a \Phalcon\Di\FactoryDefault dovrei comunque rivedere il codice, ma solo cambiando l'array services e il nome del mio metodo, non andare ad aggiungere uno special-case nel loop.

Non c'è, sembra, un modo per fare il binding di un method al proprio oggetto, ovvero come sarebbe in javascript passare il nome del metodo tipo this.methodName.bind(this).

Le funzioni native accettano array($this, 'methodName'), ma Phalcon vuole una Closure, altro non lo digerisce.

p.s.: il codice a cui mi riferisco è qui : https://github.com/phalcon/invo in particolare https://github.com/phalcon/invo/blob/master/app/library/Base/Services.phphttps://github.com/phalcon/invo/blob/master/app/Services.php