В PHP что такое замыкание и почему он использует & ldquo; use & rdquo; идентификатор?

Это работает для меня: предположим, что у меня есть эта зависимость

<dependency>
    <groupId>com.company.app</groupId>
    <artifactId>my-library</artifactId>
    <version>1.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/lib/my-library.jar</systemPath>
</dependency>

Затем добавьте путь к вашей системной зависимости вручную, как это

<Class-Path>libs/my-library-1.0.jar</Class-Path>

Full config:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <archive>
            <manifestEntries>
                <Build-Jdk>${jdk.version}</Build-Jdk>
                <Implementation-Title>${project.name}</Implementation-Title>
                <Implementation-Version>${project.version}</Implementation-Version>
                <Specification-Title>${project.name} Library</Specification-Title>
                <Specification-Version>${project.version}</Specification-Version>
                <Class-Path>libs/my-library-1.0.jar</Class-Path>
            </manifestEntries>
            <manifest>
                <addClasspath>true</addClasspath>
                <mainClass>com.company.app.MainClass</mainClass>
                <classpathPrefix>libs/</classpathPrefix>
            </manifest>
        </archive>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/libs/</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
374
задан Andrey Belykh 21 September 2018 в 03:54
поделиться

6 ответов

Вот как PHP выражает закрытие . Это вовсе не зло, и на самом деле это довольно сильно и полезно.

В основном это означает, что вы позволяете анонимной функции «захватывать» локальные переменные (в данном случае, $tax и ссылку на $total) вне ее области действия и сохранять их значения (или в случае $total ссылка на сам $total) как состояние внутри самой анонимной функции.

333
ответ дан Andrew Hare 21 September 2018 в 03:54
поделиться

До самых последних лет PHP определял свой AST, а интерпретатор PHP изолировал синтаксический анализатор от части оценки. В то время, когда вводится замыкание, синтаксический анализатор PHP тесно связан с оценкой.

Поэтому, когда замыкание было впервые введено в PHP, у интерпретатора нет способа узнать, какие переменные будут использоваться в замыкании, потому что оно еще не проанализировано. Таким образом, пользователь должен порадовать движок Zend явным импортом, выполняя домашнюю работу, которую должен сделать Zend.

Это так называемый простой способ в PHP.

0
ответ дан Zhu Jinxuan 21 September 2018 в 03:54
поделиться

Зупа проделал большую работу, объясняя замыкания с помощью «использования» и разницы между «Ранним связыванием» и «Ссылкой на переменные, которые« используются ».

Итак, я сделал пример кода с ранним связыванием переменной (= копирование):

<?php

$a = 1;
$b = 2;

$closureExampleEarlyBinding = function() use ($a, $b){
    $a++;
    $b++;
    echo "Inside \$closureExampleEarlyBinding() \$a = ".$a."<br />";
    echo "Inside \$closureExampleEarlyBinding() \$b = ".$b."<br />";    
};

echo "Before executing \$closureExampleEarlyBinding() \$a = ".$a."<br />";
echo "Before executing \$closureExampleEarlyBinding() \$b = ".$b."<br />";  

$closureExampleEarlyBinding();

echo "After executing \$closureExampleEarlyBinding() \$a = ".$a."<br />";
echo "After executing \$closureExampleEarlyBinding() \$b = ".$b."<br />";

/* this will output:
Before executing $closureExampleEarlyBinding() $a = 1
Before executing $closureExampleEarlyBinding() $b = 2
Inside $closureExampleEarlyBinding() $a = 2
Inside $closureExampleEarlyBinding() $b = 3
After executing $closureExampleEarlyBinding() $a = 1
After executing $closureExampleEarlyBinding() $b = 2
*/

?>

Пример со ссылкой на переменную (обратите внимание на символ & amp; перед переменной); 114]

<?php

$a = 1;
$b = 2;

$closureExampleReferencing = function() use (&$a, &$b){
    $a++;
    $b++;
    echo "Inside \$closureExampleReferencing() \$a = ".$a."<br />";
    echo "Inside \$closureExampleReferencing() \$b = ".$b."<br />"; 
};

echo "Before executing \$closureExampleReferencing() \$a = ".$a."<br />";
echo "Before executing \$closureExampleReferencing() \$b = ".$b."<br />";   

$closureExampleReferencing();

echo "After executing \$closureExampleReferencing() \$a = ".$a."<br />";
echo "After executing \$closureExampleReferencing() \$b = ".$b."<br />";    

/* this will output:
Before executing $closureExampleReferencing() $a = 1
Before executing $closureExampleReferencing() $b = 2
Inside $closureExampleReferencing() $a = 2
Inside $closureExampleReferencing() $b = 3
After executing $closureExampleReferencing() $a = 2
After executing $closureExampleReferencing() $b = 3
*/

?>
14
ответ дан joronimo 21 September 2018 в 03:54
поделиться

function () use () {} похоже на закрытие для PHP.

Без use функция не может получить доступ к родительской переменной области действия

$s = "hello";
$f = function () {
    echo $s;
};

$f(); // Notice: Undefined variable: s
$s = "hello";
$f = function () use ($s) {
    echo $s;
};

$f(); // hello

Значение переменной use берется из определения функции, а не при ее вызове

$s = "hello";
$f = function () use ($s) {
    echo $s;
};

$obj = "how are you?";
$f(); // hello

use переменная по ссылке с &

$s = "hello";
$f = function () use (&$s) {
    echo $s;
};

$s = "how are you?";
$f(); // how are you?
45
ответ дан Steely Wing 21 September 2018 в 03:54
поделиться

крышки прекрасны! они решают множество проблем, связанных с анонимными функциями, и делают возможным действительно элегантный код (по крайней мере, пока мы говорим о php).

Программисты javascript постоянно используют замыкания, иногда даже не подозревая об этом, потому что связанные переменные не определены явно - вот для чего «использование» в php.

Есть лучшие примеры из реальной жизни, чем приведенный выше. Допустим, вам нужно отсортировать многомерный массив по подзначению, но ключ меняется.

<?php
    function generateComparisonFunctionForKey($key) {
        return function ($left, $right) use ($key) {
            if ($left[$key] == $right[$key])
                return 0;
            else
                return ($left[$key] < $right[$key]) ? -1 : 1;
        };
    }

    $myArray = array(
        array('name' => 'Alex', 'age' => 70),
        array('name' => 'Enrico', 'age' => 25)
    );

    $sortByName = generateComparisonFunctionForKey('name');
    $sortByAge  = generateComparisonFunctionForKey('age');

    usort($myArray, $sortByName);

    usort($myArray, $sortByAge);
?>

предупреждение: непроверенный код (у меня не установлен php5.3 atm), но он должен выглядеть примерно так.

есть один недостаток: многие php-разработчики могут оказаться немного беспомощными, если вы столкнетесь с ними замыканиями.

Чтобы лучше понять замыкания замыканий, я приведу еще один пример - на этот раз в javascript. Одной из проблем является асинхронность, присущая браузеру. особенно, если речь идет о window.setTimeout(); (или -interval). Итак, вы передаете функцию в setTimeout, но вы не можете дать какие-либо параметры, потому что предоставление параметров выполняет код!

function getFunctionTextInASecond(value) {
    return function () {
        document.getElementsByName('body')[0].innerHTML = value; // "value" is the bound variable!
    }
}

var textToDisplay = prompt('text to show in a second', 'foo bar');

// this returns a function that sets the bodys innerHTML to the prompted value
var myFunction = getFunctionTextInASecond(textToDisplay);

window.setTimeout(myFunction, 1000);

myFunction возвращает функцию с неким предопределенным параметром!

Если честно, мне больше нравится php с 5.3 и анонимные функции / замыкания. пространства имен могут быть более важными, , но они намного менее сексуальны .

51
ответ дан Timm 21 September 2018 в 03:54
поделиться

Более простой ответ.

function ($quantity) use ($tax, &$total) { .. };

  1. Замыкание - это функция, назначенная переменной, поэтому вы можете передавать ее вокруг
  2. Замыкание - это отдельное пространство имен, обычно вы не можете переменные, определенные вне этого пространства имен. Приходит ключевое слово use :
  3. use позволяет получить доступ (использовать) последующие переменные внутри замыкания .
  4. Использование является ранним связыванием. Это означает, что значения переменных копируются после определения замыкания. Таким образом, изменение $tax внутри замыкания не имеет внешнего эффекта, если только он не является указателем, как объект.
  5. Вы можете передавать переменные в виде указателей, как в случае &$total. Таким образом, изменение значения $total оказывает внешнее воздействие, значение исходной переменной изменяется.
  6. Переменные, определенные внутри замыкания, также недоступны извне замыкания.
  7. Затворы и функции имеют одинаковую скорость. Да, вы можете использовать их во всех сценариях.

Как отметил @Mytskine , вероятно, лучшим подробным объяснением является RFC для замыканий . (Проголосуйте за него.)

439
ответ дан Community 21 September 2018 в 03:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: