일부 PHP 5.3.0
기능을 확인하고 있으며 사이트에서 매우 재미있게 보이는 일부 코드를 실행했습니다.
public function getTotal($tax)
{
$total = 0.00;
$callback =
/* This line here: */
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
익명 함수 에 대한 예제 중 하나입니다 .
아무도 이것에 대해 알고 있습니까? 어떤 문서? 그리고 그것은 악하게 보입니다, 그것을 사용해야합니까?
답변
이것은 PHP가 클로저를 표현하는 방법 입니다. 이것은 전혀 악한 것이 아니며 실제로는 강력하고 유용합니다.
기본적으로 이것이 의미하는 것은 익명 함수가 범위 외부의 로컬 변수 (이 경우 $tax
및 참조 $total
) 를 “캡처” 하고 해당 값 (또는 자체 $total
참조 의 경우 $total
)을 상태로 유지 하도록 허용한다는 것입니다. 익명 함수 자체
답변
더 간단한 대답.
function ($quantity) use ($tax, &$total) { .. };
- 클로저는 변수에 할당 된 함수이므로 전달할 수 있습니다
- 클로저는 별도의 네임 스페이스이므로 일반적으로이 네임 스페이스 외부에 정의 된 변수에 액세스 할 수 없습니다. 온다 사용 키워드 :
- use를 사용 하면 클로저 내부의 후속 변수에 액세스 (사용) 할 수 있습니다.
- 사용 은 초기 바인딩입니다. 이는 클로저 정의시 변수 값이 복사됨을 의미합니다. 따라서
$tax
클로저 내부를수정하면 객체와 같은 포인터가 아닌 한 외부 효과가 없습니다. - 의 경우와 같이 변수를 포인터로 전달할 수 있습니다
&$total
. 이 방법으로$total
DOES 값을 수정하면 외부 효과 가 생겨 원래 변수의 값이 변경됩니다. - 클로저 내부에 정의 된 변수는 클로저 외부에서도 액세스 할 수 없습니다.
- 클로저와 기능의 속도는 동일합니다. 예, 스크립트 전체에서 사용할 수 있습니다.
@Mytskine이 지적했듯이 아마도 가장 좋은 설명은 클로저에 대한 RFC입니다 . (이를 위해 그를 찬성하십시오.)
답변
이것은 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;
};
$s = "how are you?";
$f(); // hello
use
변수에 의한 참조 &
$s = "hello";
$f = function () use (&$s) {
echo $s;
};
$s = "how are you?";
$f(); // how are you?
답변
폐쇄는 아름답다! 그들은 익명 함수와 함께 제공되는 많은 문제를 해결하고 (최소한 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 개발자는 클로저에 직면하면 약간 무력 할 수 있습니다.
클로저의 멋진 점을 더 이해하기 위해 이번에는 자바 스크립트로 다른 예를 들어 보겠습니다. 문제 중 하나는 범위 지정과 브라우저 고유의 비동기 성입니다. 특히 window.setTimeout();
(또는-간격) 경우. 따라서 함수를 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은 사전 정의 된 일종의 매개 변수가있는 함수를 반환합니다!
솔직히 말하면, 나는 5.3 이후로 PHP와 익명 함수 / 클로저를 훨씬 더 좋아합니다. 네임 스페이스가 더 중요 할 수 있지만 훨씬 덜 섹시 합니다.
답변
Zupa는 ‘사용’을 사용하여 클로저를 설명하고 EarlyBinding과 ‘사용 된’변수를 참조하는 것의 차이점을 설명하는 훌륭한 작업을 수행했습니다.
그래서 변수의 초기 바인딩 (= 복사)으로 코드 예제를 만들었습니다.
<?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
*/
?>
변수를 참조하는 예 (변수 앞에 ‘&’문자에 주목);
<?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
*/
?>
답변
최근까지 PHP는 AST를 정의했으며 PHP 인터프리터는 파서를 평가 부분에서 분리했습니다. 클로저가 도입되는 동안, PHP 파서는 평가와 밀접한 관련이 있습니다.
따라서 클로저가 처음 PHP에 도입되었을 때, 인터프리터는 아직 파싱되지 않았기 때문에 클로저에 어떤 변수가 사용 될지 알 수있는 방법이 없습니다. 따라서 사용자는 zend가해야 할 과제를 수행하면서 명시적인 가져 오기를 통해 zend 엔진을 기뻐해야합니다.
이것은 PHP에서 소위 간단한 방법입니다.