Verschlüsse in PHP… was genau sind sie und wann müssten Sie sie verwenden?

80

Also programmiere ich auf eine nette, aktuelle, objektorientierte Weise mit. Ich benutze regelmäßig die verschiedenen Aspekte von OOP, die PHP implementiert, aber ich frage mich, wann ich möglicherweise Verschlüsse verwenden muss. Gibt es Experten, die Aufschluss darüber geben können, wann es sinnvoll wäre, Schließungen vorzunehmen?

rg88
quelle

Antworten:

80

PHP wird Schließungen in 5.3 nativ unterstützen. Ein Verschluss ist gut, wenn Sie eine lokale Funktion wünschen, die nur für einen kleinen, spezifischen Zweck verwendet wird. Der RFC für Verschlüsse gibt ein gutes Beispiel:

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

Auf diese Weise können Sie die replacementFunktion lokal innerhalb definieren replace_spaces(), sodass dies nicht der Fall ist :
1) Überladen des globalen Namespace
2 ) Lassen Sie die Leute drei Jahre später fragen, warum eine global definierte Funktion nur innerhalb einer anderen Funktion verwendet wird

Es hält die Dinge organisiert. Beachten Sie, dass die Funktion selbst keinen Namen hat, sondern lediglich als Referenz definiert und zugewiesen wird $replacement.

Aber denken Sie daran, Sie müssen auf PHP 5.3 warten :)

Sie können auch mit dem Schlüsselwort auf Variablen außerhalb des Gültigkeitsbereichs zugreifen use. Betrachten Sie dieses Beispiel.

// Set a multiplier  
 $multiplier = 3;

// Create a list of numbers  
 $numbers = array(1,2,3,4);

// Use array_walk to iterate  
 // through the list and multiply  
 array_walk($numbers, function($number) use($multiplier){  
 echo $number * $multiplier;  
 }); 

Eine ausgezeichnete Erklärung wird hier gegeben. Was sind PHP-Lambdas und Verschlüsse?

Dirtside
quelle
1
Dies ist eine großartige Erklärung. +1
David J Eddy
4
Mir hat die Erklärung gefallen, warum Sie Verschlüsse verwenden würden. Die meisten Leute verstehen das nicht wirklich. +1
Carrie Kendall
10
Dies ist eine Erklärung für anonyme Funktionen, keine Erklärung für Schließungen. Anonyme Funktionen sind, wie Sie sagen, genau wie benannte Funktionen, außer dass sie nicht global sind. Closures hingegen sind Funktionen, die lexikalisch begrenzte freie Variablen enthalten (deklariert mit "use"). dh. Sie können Werte aus dem Bereich, in dem sie deklariert sind, kopieren und referenzieren, selbst nachdem alles andere durch Müll gesammelt wurde.
Warbo
@ Warbo Das ist wahr; Zu der Zeit habe ich den Unterschied zwischen einer anonymen Funktion und einem Abschluss nicht wirklich erkannt. Verschlüsse sind wirklich nur dann sinnvoll, wenn Sie anonyme Funktionen ausführen, aber bis heute finde ich immer noch "Erklärungen", was ein Verschluss ist (wie meiner vor 7 Jahren ;-)), die den Umfang des Aspekts nicht erklären.
Dirtside
Aus diesem Grund habe ich gesagt, schauen Sie sich JavaScript an, wo Verschlüsse häufig verwendet werden - aber denken Sie daran, dass die Regeln für variable Bereiche in PHP unterschiedlich sind.
Rolf
16

Wenn Sie in Zukunft eine Funktion benötigen, die eine Aufgabe ausführt, für die Sie sich jetzt entschieden haben.

Wenn Sie beispielsweise eine Konfigurationsdatei lesen und einer der Parameter angibt, dass dies hash_methodfür Ihren Algorithmus multiplynicht der squareFall ist , können Sie einen Abschluss erstellen, der überall dort verwendet wird, wo Sie etwas hashen müssen.

Der Verschluss kann in (zum Beispiel) erstellt werden config_parser(); Es wird eine Funktion erstellt, die unter do_hash_method()Verwendung von Variablen local to config_parser()(aus der Konfigurationsdatei) aufgerufen wird . Immer wenn do_hash_method()es aufgerufen wird, hat es Zugriff auf Variablen im lokalen Bereich von config_parser(), obwohl es in diesem Bereich nicht aufgerufen wird.

Ein hoffentlich gutes hypothetisches Beispiel:

function config_parser()
{
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
        function do_hash_method($var)
        {
            // $hash_method is from the parent's local scope
            if ($hash_method == 'multiply')
                return $var * $var;
            else
                return $var ^ $var;
        }
    }
}


function hashme($val)
{
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
}
Dan Udey
quelle
Ich kann dieses Beispiel nicht einfach kopieren, einfügen und ausführen. Bevorzugt ein Beispiel, das ich einfach ausführen kann.
Kim Stacks
3
Diese Antwort ist schlecht. Dies ist eine bedeutungslose Aussage: "Wenn Sie in Zukunft eine Funktion benötigen, die eine Aufgabe ausführt, für die Sie sich jetzt entschieden haben."
Entspannen in Zypern
15

Neben den technischen Details sind Verschlüsse eine Grundvoraussetzung für einen Programmierstil, der als funktionsorientierte Programmierung bezeichnet wird. Ein Abschluss wird ungefähr für das verwendet, wofür Sie ein Objekt in der objektorientierten Programmierung verwenden. Es bindet Daten (Variablen) mit einem Code (einer Funktion) zusammen, den Sie dann an eine andere Stelle weitergeben können. Als solche wirken sie sich auf die Art und Weise aus, wie Sie Programme schreiben, oder - wenn Sie die Art und Weise, wie Sie Ihre Programme schreiben, nicht ändern - haben sie überhaupt keine Auswirkungen.

Im Kontext von PHP sind sie etwas seltsam, da PHP bereits das klassenbasierte, objektorientierte Paradigma sowie das ältere prozedurale Paradigma stark beansprucht. Normalerweise haben Sprachen mit Verschlüssen den vollen lexikalischen Geltungsbereich. Um die Abwärtskompatibilität aufrechtzuerhalten, wird PHP dies nicht erhalten, was bedeutet, dass die Schließungen hier etwas anders sein werden als in anderen Sprachen. Ich denke, wir müssen noch genau sehen, wie sie verwendet werden.

troelskn
quelle
10

Ich mag den Kontext, den Troelskns Post bietet. Wenn ich so etwas wie Dan Udeys Beispiel in PHP machen möchte, verwende ich das OO-Strategiemuster. Meiner Meinung nach ist dies viel besser als die Einführung einer neuen globalen Funktion, deren Verhalten zur Laufzeit bestimmt wird.

http://en.wikipedia.org/wiki/Strategy_pattern

Sie können Funktionen und Methoden auch mit einer Variablen aufrufen, die den Methodennamen in PHP enthält. Eine andere Einstellung zu Dans Beispiel wäre also ungefähr so:

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }

        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

Wenn Sie möchten, dass es überall verfügbar ist, können Sie natürlich einfach alles statisch machen ...

Grossvogel
quelle
2

Ein Abschluss ist im Grunde eine Funktion, für die Sie die Definition in einem Kontext schreiben, aber in einem anderen Kontext ausführen. Javascript hat mir sehr geholfen, diese zu verstehen, da sie überall in JavaScript verwendet werden.

In PHP sind sie weniger effektiv als in JavaScript, da sich der Umfang und die Zugänglichkeit von "globalen" (oder "externen") Variablen innerhalb von Funktionen unterscheiden. Ab PHP 5.4 können Closures jedoch auf das $ this-Objekt zugreifen, wenn sie in einem Objekt ausgeführt werden. Dies macht sie wesentlich effektiver.

Darum geht es bei Schließungen, und es sollte ausreichen, um zu verstehen, was oben geschrieben steht.

Dies bedeutet, dass es möglich sein sollte, irgendwo eine Funktionsdefinition zu schreiben und die Variable $ this in der Funktionsdefinition zu verwenden, dann die Funktionsdefinition einer Variablen zuzuweisen (andere haben Beispiele für die Syntax angegeben) und diese Variable dann an ein Objekt zu übergeben Wenn Sie es im Objektkontext aufrufen, kann die Funktion dann über $ this auf das Objekt zugreifen und es bearbeiten, als wäre es nur eine andere Methode, obwohl es nicht in der Klassendefinition dieses Objekts definiert ist, sondern an einer anderen Stelle.

Wenn es nicht sehr klar ist, machen Sie sich keine Sorgen, es wird klar, sobald Sie sie verwenden.

Rolf
quelle
Ehrlich gesagt, mir ist das überhaupt nicht klar, auch für mich, den Autor. Grundsätzlich sage ich: Um zu erfahren, welche Abschlüsse sie sind, überprüfen Sie sie in JavaScript. Beachten Sie jedoch, dass der variable Bereich zwischen JavaScript und PHP unterschiedlich ist.
Rolf
1

Grundsätzlich sind Closure die inneren Funktionen, die Zugriff auf die äußeren Variablen haben und als Rückruffunktion für eine anonyme Funktion (Funktionen, die keinen Namen haben) verwendet werden.

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;
Harter Gehlot
quelle
$param='captain'in func sayhello()ist eine lokale Variable zu func sayhello(). $param='ironman'oben sayhello()ist globale Variable. Wenn Sie nur eine $ param Variable in Ihrem Skript machen möchten , sollten Sie anrufen: global $param;innerhalb sayhello()func
vlakov
0

Hier sind Beispiele für Verschlüsse in PHP

// Author: [email protected]
// Publish on: 2017-08-28

class users
{
    private $users = null;
    private $i = 5;

    function __construct(){
        // Get users from database
        $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
    }

    function displayUsers($callback){
        for($n=0; $n<=$this->i; $n++){
            echo  $callback($this->users[$n], $n);
        }
    }

    function showUsers($callback){
        return $callback($this->users);

    }

    function getUserByID($id, $callback){
        $user = isset($this->users[$id]) ? $this->users[$id] : null;
        return $callback($user);
    }

}

$u = new users();

$u->displayUsers(function($username, $userID){
    echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
    foreach($users as $user){
        echo strtoupper($user).' ';
    }

});

$x = $u->getUserByID(2, function($user){

    return "<h1>$user</h1>";
});

echo ($x);

Ausgabe:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c
Hisham Dalal
quelle