Closure en objecten

Opmerking: PHP 5.3 Beta heeft geen ondersteuning meer voor $this binnen een closure omdat men het niet eens kon worden over de werking. De hieronder beschreven werking slaat op de alfa versies van PHP 5.3

Hoe zit het met $this binnen closures, en waar zitten de caveats?

Vandaag op het programma:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

class Foo {
    
    protected $greeting;
    
    public $greet;
    
    public function __construct() {
        
        $this->greeting = 'Hello ';
        
        $this->greet = function($subject) {
            echo $this->greeting . $subject;
        };
    }
}


$foo = new Foo();
?>


Foo::$greet is de closure die gebruik maakt van protected Foo::$greeting. Dit mag, want de closure wordt in een object-context gemaakt. $this hoef je niet te importeren, net zoals je dat niet hoeft in __construct. Daarnaast zijn wijzigingen die je doet op $this direct wijzigingen op $foo, zoals verwacht.

Hoe roep je nu $foo->greet aan? Eerste idee wat bij mij opkomt is dan:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$foo
->greet('Jelmer');
?>

WTF?!: Boooh! Dat werkt niet. De klasse Foo heeft geen method genaamd 'greet'. Maar een reference (reference? Zie volgende pagina!) maken werkt wel.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
$greeter
= $foo->greet;
$greeter('Jelmer');

/* Resultaat:
Hello Jelmer
*/

?>


* Magic Method __invoke *

Maar wat is een closure nu werkelijk binnen PHP?
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
<?php
var_dump(function($x, $y) {
    return $x * $y;
});

/* resultaat:
object(Closure)#1 (0) {
}
*/

?>

Vergelijk dat met de oude create_function:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
var_dump(create_function('$x, $y', 'return $x * $y;'));
/* resultaat:
string(9) "lambda_1"
*/

?>

Een closure is een object in PHP. Vandaar dat ik een pagina terug ook sprak over een reference. Een closure kopieer je niet (sterker nog, clone werkt niet) maar verwijs je naar zoals standaard is bij objecten in PHP 5.

Maar als Closure een klasse is, kan je hem ook extenden? Nee helaas, Closure is een final class, wat inhoudt dat je hem niet kan uitbreiden. Je kan hem ook niet direct vanuit PHP instantiƫren:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
$x
= new Closure();
/* Resultaat:
PHP Fatal error: Instantiation of 'Closure' is not allowed
*/

?>


Maaaarrrr... Closure heeft wel een method genaamd '__invoke'! Guess what:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
<?php
$foo
= function($x, $y) {
    return $x * $y;
};


echo $foo->__invoke(2, 3);

/* resultaat:
6
*/

?>


En het wordt leuker!
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Cube {
    
    protected $depth;
    
    public function __construct($depth) {
        $this->depth = $depth;
    }

    
    public function __invoke($x, $y) {
        return $this->depth * $x * $y;
    }
}


$cube = new Cube(4);
echo $cube(4, 4);

/* Resultaat:
64
*/

?>

Dit betekent dat je voortaan instanties van klassen met een __invoke-method direct kan aanroepen of kan opgeven als callback: Dit zal werken zonder gemekker:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
ob_start($cube);
?>

.. het doet alleen niets nuttigs :)

« Lees de omschrijving en reacties

Inhoudsopgave

  1. Je eerste closure
  2. Variabelen importeren in een closure
  3. De scope van 'use'
  4. Closure en objecten
  5. WTF?! - de opsomming
  6. Disclaimer

PHP tutorial opties

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.