>  기사  >  백엔드 개발  >  새로운 추상 구문 트리(AST)로 인해 PHP7에 적용된 변경 사항

새로운 추상 구문 트리(AST)로 인해 PHP7에 적용된 변경 사항

Guanhui
Guanhui앞으로
2020-05-14 11:12:072983검색

새로운 추상 구문 트리(AST)로 인해 PHP7에 적용된 변경 사항

이 글의 내용은 대부분 AST의 RFC 문서인 https://wiki.php.net/rfc/abstract_syntax_tree를 기반으로 작성되었습니다. .

이 기사에서는 추상 구문 트리가 무엇인지 설명하지 않습니다. 이 기사에서는 AST가 PHP에 가져오는 몇 가지 변경 사항만 설명합니다.

새로운 실행 프로세스

PHP7 핵심의 중요한 변화는 AST의 추가입니다. PHP5에서 PHP 스크립트에서 opcode까지의 실행 프로세스는 다음과 같습니다.

1. Lexing: 어휘 스캐닝 분석, 소스 파일을 토큰 스트림으로 변환

2 구문 분석, 이 단계에서 op 배열 생성.

3. PHP7에서는 더 이상 구문 분석 단계에서 op 배열이 직접 생성되지 않지만 AST가 먼저 생성되므로 프로세스에 한 단계가 더 있습니다:

4. 렉싱: 어휘 스캐닝 분석, 소스 파일을 변환 토큰 스트림;

5 , 구문 분석, 토큰 스트림에서 추상 구문 트리 생성

6. 추상 구문 트리에서 연산 배열 생성.

실행 시간 및 메모리 소모

위 단계에서 이전 과정보다 한 단계 더 진행되므로 상식적으로 보면 프로그램의 실행 시간과 메모리 사용량이 늘어나게 됩니다. 하지만 실제로는 메모리 사용량이 늘어난 것은 사실이지만 실행 시간은 줄어들었습니다.

소형(코드 약 100라인), 중형(약 700라인), 대형(약 2800라인) 세 가지 스크립트를 테스트하여 얻은 결과는 다음과 같습니다. 테스트 스크립트: https://gist.github.com /nikic/289b0c7538b46c2220bc

각 파일을 100번 컴파일하는 실행 시간(기사의 테스트 결과는 PHP7이 여전히 PHP-NG로 불렸던 14년의 것임을 참고하세요):

대형 php-ng SMALL

php- ngㅋㅋㅋ 2초 1.268초 -17.7%
6.703s 5.736s -16.9%
단일 컴파일의 메모리 최대치:
php-as t diff
378kB


414kB

+9.5%대형단일 컴파일의 테스트 결과는 실제 사용법을 나타내지 않을 수 있습니다. 다음은 PhpParser를 사용한 전체 프로젝트 테스트의 결과입니다. php-ngphp-astdiffTIME25.5ms

MEDIUM
507kB 643kB +26.8%
1084kB 1857kB +71.3%

22.8ms

-11.8%

테스트 결과, AST를 사용한 후 프로그램의 전체 실행 시간이 약 10%~15% 향상되었지만 메모리 소비도 증가하는 것으로 나타났습니다. 대용량 파일을 한 번 컴파일할 때 그 증가는 명백하지만 그리 심각한 수준은 아닙니다. 전체 프로젝트 실행 과정에서 문제가 발생합니다.

또한 위의 결과는 모두 Opcache를 사용하지 않은 결과이므로 프로덕션 환경에서 Opcache를 켜면 메모리 소비 증가는 큰 문제가 되지 않습니다.

Semantic Changes

단순한 시간 최적화라면 AST를 사용하는 충분한 이유가 되지 않는 것 같습니다. 실제로 AST 구현은 시간 최적화 고려사항이 아니라 구문 문제를 해결하기 위한 것입니다. 의미론의 몇 가지 변화를 살펴보겠습니다.

yield에는 괄호가 필요하지 않습니다.

PHP5 구현에서 표현식 컨텍스트(예: 할당 표현식의 오른쪽)에서 Yield를 사용하는 경우 Yield 선언 주위에 괄호를 사용해야 합니다.

<?php
$result = yield fn();   // 不合法的
$result = (yield fn()); // 合法的

This 이 동작은 단순히 PHP5 구현의 제한 때문입니다. PHP7에서는 괄호가 더 이상 필요하지 않습니다. 따라서 다음 작성 방법도 적법합니다.

<?php
$result = yield;
$result = yield $v;
$result = yield $k => $v;

물론 Yield의 적용 시나리오를 따라야 합니다.

괄호는 동작에 영향을 주지 않습니다

PHP5에서 ($foo)['bar'] = 'baz'와 $foo['bar'] = 'baz'는 다른 의미를 갖습니다. 사실, 이전 작성 방법은 불법이며 다음과 같은 오류가 발생합니다:

<?php
($foo)[&#39;bar&#39;] = &#39;baz&#39;;
# PHP Parse error: Syntax error, unexpected &#39;[&#39; on line 1

그러나 PHP7에서는 두 가지 작성 방법이 같은 의미입니다.

마찬가지로 함수의 매개변수가 괄호로 묶인 경우 유형 검사에 문제가 있습니다. 이 문제는 PHP7에서도 해결되었습니다.

<?php
function func() {
    return [];
}

function byRef(array &$a) {
}

byRef((func()));

위 코드는 byRef(func()를 호출하지 않는 한 PHP5에서 경보를 울리지 않습니다. ) ) 이지만 PHP7에서는 func() 양쪽에 괄호 유무에 관계없이 다음 오류가 발생합니다.

PHP Strict standards: Only variables should be passed by reference ...

list() 변경

list 키워드 동작이 많이 변경되었습니다. 리스트가 변수에 값을 할당하는 순서(동시에 등호 주위의 순서)는 예전에는 오른쪽에서 왼쪽이었지만 지금은 왼쪽에서 오른쪽입니다:

<?php
list($array[], $array[], $array[]) = [1, 2, 3];
var_dump($array);

// PHP5: $array = [3, 2, 1]
// PHP7: $array = [1, 2, 3]

# 注意这里的左右的顺序指的是等号左右同时的顺序,
# list($a, $b) = [1, 2] 这种使用中 $a == 1, $b == 2 是没有疑问的。

위 변경 이유는 다음과 같습니다. 왜냐하면 PHP5의 할당 과정에서 3이 배열에 처음으로 채워지고 1이 마지막으로 채워지지만 이제 순서가 변경되었기 때문입니다.

동일한 변경 사항은 다음과 같습니다.

<?php
$a = [1, 2];
list($a, $b) = $a;

// PHP5: $a = 1, $b = 2
// PHP7: $a = 1, $b = null + "Undefined index 1"

이전 할당 프로세스에서 $b가 먼저 2를 얻은 다음 $a의 값이 1이 되었지만 이제 $a가 먼저 1이 되어 더 이상 배열이 아니기 때문입니다. . 따라서 $b는 null이 됩니다.

목록은 이제 오프셋당 한 번만 액세스됩니다.

<?php
list(list($a, $b)) = $array;

// PHP5:
$b = $array[0][1];
$a = $array[0][0];

// PHP7:
// 会产生一个中间变量,得到 $array[0] 的值
$_tmp = $array[0];
$a = $_tmp[0];
$b = $_tmp[1];

빈 목록 멤버는 이제 모두 금지됩니다. 이전에는 특정 경우에만 가능했습니다.

<?php
list() = $a;           // 不合法
list($b, list()) = $a; // 不合法
foreach ($a as list()) // 不合法 (PHP5 中也不合法)

참조 할당 순서

참조 할당 순서 PHP5에서는 오른쪽부터입니다. to left, 현재 시제는 왼쪽에서 오른쪽으로:

<?php
$obj = new stdClass;
$obj->a = &$obj->b;
$obj->b = 1;
var_dump($obj);

// PHP5:
object(stdClass)#1 (2) {
  ["b"] => &int(1)
  ["a"] => &int(1)
}

// PHP7:
object(stdClass)#1 (2) {
  ["a"] => &int(1)
  ["b"] => &int(1)
}

__clone 메소드를 직접 호출할 수 있습니다

이제 $obj->__clone()을 사용하여 __clone 메소드를 직접 호출할 수 있습니다. __clone은 이전에 직접 호출이 금지된 유일한 매직 메소드였습니다. 이전에는 다음과 같은 오류가 발생했습니다.

Fatal error: Cannot call __clone() method on objects - use &#39;clone $obj&#39; instead in ...

변수 구문 일관성

AST는 RFC에서 제안된 다른 제안에서 보고된 일부 구문 일관성 문제도 해결했습니다. https://wiki.php.net/rfc/uniform_variable_syntax.

새 구현에서는 이전 문법 표현의 의미가 현재와 다소 다릅니다. 자세한 내용은 다음 표를 참조하세요.


MEMORY
2360kB 2482kB +5.1%
${$foo[ 'bar ']['baz']}($$foo)['bar']['baz']
Expression PHP5 PHP7
$$foo['bar']['baz']$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()

$foo-> ['baz']$foo->{$bar['baz']}

🎜($foo->$bar)[' baz' ]🎜🎜🎜🎜$foo->$bar['baz']()🎜🎜$foo->{$bar['baz'] }( )🎜🎜($foo->$bar)['baz']()🎜🎜🎜🎜Foo::$bar['baz']( )🎜🎜<code>Foo::{$bar['baz']}()🎜🎜(Foo::$bar)['baz']()🎜 🎜🎜🎜🎜전체적으로 이전 순서는 오른쪽에서 왼쪽이었지만 이제는 왼쪽에서 오른쪽이며 괄호가 동작에 영향을 주지 않는다는 원칙도 따릅니다. 이러한 복잡한 변수 작성 방식은 실제 개발 시 주의가 필요합니다. 🎜🎜추천 튜토리얼: "🎜PHP7🎜"🎜

위 내용은 새로운 추상 구문 트리(AST)로 인해 PHP7에 적용된 변경 사항의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제