만인이 기대하는 세계 최고의 프로그래밍 언어 PHP 최신판 PHP8이 2020-11-26 정식 버전으로 출시됐다.
이름 지정 매개 변수, 결합 유형, 주석, 생성자 속성 향상, match 표현식 등 많은 새로운 기능과 최적화 항목을 포함합니다.nullsafe 연산자, JIT를 비롯하여 유형 시스템, 오류 처리, 문법적 일관성을 개선하였습니다.
오늘은 이러한 주요 업데이트 사항을 구체적으로 살펴보겠습니다.
카테고리
1. JIT 컴파일 (Just In Time Compilation)
1. Opcache를 열지 않음
2. Opcacheh를 켠 후 실행 과정
3. JIT 오픈 후 실행 과정
4. JIT의 구성.
5. 성능 대비
2. 이름 지정 인자 (Nameed arguments)
3. 유니온 타입 (Union Type)
4. match 표현식 (Match Expressions)
5. 컨스트럭터 속성 상승 (constructor property promotion)
5. 주해 (Attributes)
6. Nullsafe 연산자 (Nullsafe Operator)
7. 보다 합리적인 문자열과 숫자 비교
1. JIT 컴파일 (Just In Time Compilation)
JIT는 PHP에서 가장 기대되는 기능 중 하나인 셈이다. JIT 컴파일 기술은 OpCodes를 기계 코드로 컴파일함으로써 발전한다.한 걸음으로 코드의 실행 속도를 향상시켰다.CPU 집약적인 계산으로 성능이 대폭 향상되었습니다.
아래 그림은 대조적인 것으로, JIT를 연 후의 성능 대비 성능 향상이 매우 뚜렷하다고 할 수 있습니다
위에서 언급한 바와 같이 JIT는 OpCodes를 기반으로 하고 있으며, 간단한 분석으로 PHP를 실행하는 원리입니다.
1. Opcache를 열지 않음
Opcache를 켜지 않을 때 PHP코드가 수행하는 단계:
PHP 코드를 실행합니다. 각각 다음 4단계를 수행합니다.
1.Lexing, PHP코드 변환언어 조각( Tokens)
2.Parsing, Tokens 단순하고 의미 있는 추상 구문 트리 표현식으로 변환
3. Compilation, 표현하기Opcodes로 컴파일하기
4.Execution, Zend 인용옵코데즈 순차적 실행
2. Opcacheh를 켠 후 실행과정
Opcache를 켜면 메모리 공유 캐시 계층을 추가하여 컴파일된 Opcodes를 캐시하고 다음 번에 동일한 코드를 실행할 때 zend VM 엔진에 직접 꺼내어 실행합니다.
이렇게 하면 Lexing, Parsing, Compiling의 3단계를 생략하고 프로그램 실행 속도를 빠르게 할 수 있습니다.
3. JIT 오픈 후 실행 과정
JIT 지원을 켜면 JIT는 Opcache 최적화 후 Runtime의 정보를 결합하여 다시 최적화하여 직접 머신 코드를 생성하고 캐싱합니다.다음에 같은 코드를 실행할 때는, 머신 코드를 캐시로부터 직접 꺼내어 실행합니다.
이에 따라 Zend VM 엔진이 Opcodes에서 기계코드를 생성하는 단계를 생략할 수 있게 됐다.
4. JIT의 구성.
JIT는 opcache 기반이기 때문에 php.ini에서 opcode를 먼저 켜야 합니다
zend_extension = opcache.so
opcache.enable = 1
opcache.enable_cli = 1
그리고 JIT만의 세팅입니다
opcache.jit=1205
opcache.jit_buffer_size=64M
opcache.jit 1205 이 네 개의 숫자는 네 개의 구성 요소로 구성됩니다
1,기계 코드 포인트를 생성할 때 AVX 명령을 사용할지 여부는 CPU 지원이 필요합니다. (0,1)
2, 레지스터 할당 정책: (0~2)
3, JIT 트리거 전략: (0~5)
4, JIT 최적화 전략, 수치가 높을수록 최적화 강도 : (0~5)
이 중 4가지 항목의 구체적인 값은 다음과 같다.
기계 코드 포인트를 생성할 때 AVX 명령을 사용할지 여부는 CPU 지원이 필요합니다.
0: 사용하지 않음
1: 사용
레지스터 할당 정책:
0: 레지스터 할당 안 함
1: 로컬(block) 도메인 할당
2: 전역 (function) 도메인 할당
JIT 트리거 전략:
0: PHP 스크립트 탑재들어올 때 지트가
1: 함수 첫 번째실행 시 JIT
2: 1회 실행 후JIT 호출 건수가 가장 많은 %(opc)ache.prof_threshold * 100)의 함수
3: 함수/방법N(N과 opcache.ji를 초과하여 실행됨t_hot_func 관련)다음 JIT
4: 당함수 방법댓글에 @jit이 들어가 있을 때 JI를 하고T
5: Tra가 되면ce가 N회 이상 실행됨(그리고 opcache.jit_hot_loop, jit_hot_return 등에 관한 것)나중에 JIT
JIT 최적화 전략, 수값이 클수록 최적화의 힘:
0: 불지트
1: oplin을 하다e 사이의 점프 부분의 JIT
2: 가렴 opcode Handler 호출
3: 유형별 추론함수 급을 하는 JIT
4: 형식 기반 추론,프로세스 호출 기능 수준 JIT
5: 유형별 추정,프로세스콜그래픽스크립트수준의JIT
복잡해 보이는데, 아무튼매듭을 짓자.
가능한 12x5형을 사용해라.이 때 가장 효과적일 것이다.x의 경우 스크립트 수준이라면 0,웹 서비스형이라면 테스트 결과에 따라 3 또는 5를 선택할 수 있습니다.
5. 성능 대비
저희가 각각 php7에 있어서php8 이하 동일한 테스트 코드를 실행한다., 성능 대비 상황을 살펴보자.
PHP7:
$ php -d opcache.jit_buffer_size=0 Zend/bench.php
simple 0.006
simplecall 0.003
simpleucall 0.003
simpleudcall 0.003
mandel 0.023
mandel2 0.036
ackermann(7) 0.012
ary(50000) 0.003
ary2(50000) 0.002
ary3(2000) 0.029
fibo(30) 0.045
hash1(50000) 0.006
hash2(500) 0.007
heapsort(20000) 0.017
matrix(20) 0.015
nestedloop(12) 0.014
sieve(30) 0.008
strcat(200000) 0.003
------------------------
Total 0.236
PHP8:
php -d opcache.jit_buffer_size=64M -d opcache.jit=1205 Zend/bench.php
simple 0.002
simple 0.001
simplecall 0.000
simpleucall 0.001
simpleudcall 0.000
mandel 0.005
mandel2 0.006
ackermann(7) 0.006
ary(50000) 0.002
ary2(50000) 0.002
ary3(2000) 0.010
fibo(30) 0.019
hash1(50000) 0.004
hash2(500) 0.003
heapsort(20000) 0.008
matrix(20) 0.008
nestedloop(12) 0.005
sieve(30) 0.002
strcat(200000) 0.002
------------------------
Total 0.085
대비: Zend/bench.php의 경우 JIT를 켜면 시간이 거의(70%), 성능이 거의(2배) 향상됩니다.
2. 이름 지정 인자 (Nameed arguments)
함수를 만들 때, 예를 들어 다음과 같습니다
function Get($name, $age, $sex)
{
//
}
이 함수를 호출할 때, 우리는 순차적으로 인수를 입력해야 한다
Get("jack", 18, 1)
하지만 PHP8에서는 이렇게 할 수 있다.
Get(name: "jack", age: 18, sex: 1)
인수를 받는 동시에 이 인수의 이름을 지정합니다.이런 장점은 순서를 바꿔서 전달할 수 있다는 것입니다
Get(name: "jack", age: 18, sex: 1)
Get(age: 18, name: "jack",sex: 1)
Get(sex: 1, age: 18, name: "jack")
기본값이 있는 매개 변수에 대해서, 우리는 이 값을 건너뛰고 매개 변수를 통해서 값을 전달할 수 있습니다
function Create($name, $sex = 1, $age)
{
//
}
Create(name: "jack", age: 18)
물론 신구 방식도 함께 사용할 수 있습니다
Create("jack", age: 18)
이 새로운 기능, 이상하게 보일지 몰라도 별로 쓸모가 없을 것 같아-_-||
3. 유니온 타입 (Union Type)
PHP7에서 강제 식별을 실행한 후 함수에 대한 변수 유형과 반환 값유형, 모두 유일하게 고정되어 있습니다. 예
function Get(string $name, int $age, int $sex): bool {}
하지만 이는 PHP가 약한 언어인 것과 배치돼 전체적인 유연성은 크게 떨어진다.PHP8에서 우리는 연합 유형을 사용할 수 있다
function Get(string|int $name, int $age, int $sex): bool|string {}
이렇게 되면 강제 유형을 제한할 수 있고 다양한 유형으로 확대될 수 있다.
관청의 한 예를 보자:
class Number {
private int|float $number;
public function setNumber(int|float $number): void {
$this->number = $number;
}
public function getNumber(): int|float {
return $this->number;
}
}
4. match 표현식 (Match Expressions)
PHP8 문법 설탕에 1개의 문법 표현식이 추가되었습니다: match, 그것과 switch case는 약간 같은 점이 있지만, 또 편리함도 많아, 우리는 각각 비교해 본다
switch ($input) {
case "true":
$result = 1;
break;
case "false":
$result = 0;
break;
case "null":
$result = NULL;
break;
}
PHP 8가지에서 match 표현식으로 쓸 수 있어 더욱 쉽고 편리합니다
$result = match($input) {
"true" => 1,
"false" => 0,
"null" => NULL,
};
어메이징인지 아닌지, 우리는 switch가 하나의 case를 맞추면 break 키워드를 넣어야 한다는 것을 알고 있습니다. 모두 얼마만큼 이 구덩이를 밟았으리라 믿습니다.이제 매치 키워드가 있으면 이 구덩이를 쉽게 빠져나갈 수 있고, 바로 값을 되돌려 바로 $result에 값을 매길 수 있다.
마찬가지로 switch의 여러 case가 하나의 블록인 것처럼 match의 여러 조건도 함께 쓸 수 있다
$result = match($input) {
"true", "on" => 1,
"false", "off" => 0,
"null", "empty", "NaN" => NULL,
};
switch와 달리, 우리는 예전에 switch를 사용했을 때 이런 기괴한 문제를 자주 겪을 수 있다는 점에 유의해야 한다
$input = "2 person";
switch ($input) {
case 2:
echo "bad";
break;
}
//출력: bad
bad가 출력된 것은 스위치에 느슨한 비교가 있었기 때문==이라는 것을 알 수 있다.match는 이 문제가 발생하지 않습니다. 엄격한 비교 ===를 사용합니다. 즉, 값과 유형이 모두 동일합니다.
그리고 input이 match의 모든 조건을 충족시키지 못할 때 match는 UnhandledMatchError exception을 던진다.
5. 컨스트럭터 속성 상승 (constructor property promotion)
이것은 다소 어색하게 들릴 수 있습니다. 간단히 말해서, 우리는 클래스의 구조 함수 __construct에 클래스 속성을 명시하고 할당할 수 있습니다. 미리 정의할 필요가 없습니다.
PHP8 이전에, 우리는 일반적으로 멤버 변수를 먼저 설정한 다음 구성 또는 어떤 방법으로 값을 할당하는 클래스를 정의한다.예
class Point {
public float $x;
public float $y;
public float $z;
public function __construct(float $x = 0.0,float $y = 0.0,float $z = 0.0) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
PHP 8종은 이렇게 쓸 수 있으며 정의를 괄호 파라미터에 넣는다
class Point {
public function __construct(
public float $x = 0.0,
public float $y = 0.0,
public float $z = 0.0,
) {}
}
이런 표기법은 좀 소란스럽긴 하지만 코드량이 일부 생략된 것은 사실이다.
5. 주해 (Attributes)
주해는 PHP 8종 1개의 큰 업데이트인 셈이다.새로 추가된 주해가 원래의 것을 양보하다주석이 프로그래밍할 수 있는 능력이 생기면, 우리는 주석을 활용할 수 있다.설정 및 자동 문서 작성을 위한 솔루션입니다.
먼저 php8 중 1개의 주기의 예를 본다.
#[Params("Foo", "argument")]
#[See("https://xxxxxxxx/xxxx/xxx.html")]
#[Route("/api/posts/{id}", methods: ["GET"], return: "bool")]
function dummy($argument) {}
이 문법은 좀 이상해보여요, 전에 흔히 볼 수 있었던 주석 @param과는 좀 다른 것 같아요
#[Name(Arguments)]
#[Name(Argunment1, Arguments2, ArgumentN)]
#[Name1(Argument), Name2(Argument), Name3(Argument)]
주기의 내용은 다음과 같이 반사적으로 얻을 수 있습니다
$ref = new ReflectionFunction("dummy");
var_dump($ref->getAttributes("Params")[0]->getName());
var_dump($ref->getAttributes("Params")[0]->getArguments());
var_dump($ref->getAttributes("See")[0]->getName());
var_dump($ref->getAttributes("See")[0]->getArguments());
var_dump($ref->getAttributes("Route")[0]->getArguments());
인쇄 결과를 봅니다
string(6) "Params"
array(2) {
[0]=>
string(3) "Foo"
[1]=>
string(8) "argument"
}
string(3) "See"
array(1) {
[0]=>
string(30) "https://xxxxxxxx/xxxx/xxx.html"
}
array(3) {
[0]=>
string(15) "/api/posts/{id}"
["methods"]=>
array(1) {
[0]=>
string(3) "GET"
}
["return"]=>
string(4) "bool"
}
주해가 #주석이기 때문에 php8이 아닌 환경에서도 문법 오류가 발생하지 않는다.
6. Nullsafe 연산자 (Nullsafe Operator)
Nullsafe 연산자는 다음과 같이 씁니다. ->
null을 확인하는 조건 없이 새 nullsafe 연산자로 연쇄 호출할 수 있습니다. 체인의 한 요소가 실패하면 전체 체인이 중단되고 Null로 인식됩니다.
열을 보면 php7에서 다음과 같이 사용됩니다
$country = null;
if ($session !== null) {
$user = $session->user;
if ($user !== null) {
$address = $user->getAddress();
if ($address !== null) {
$country = $address->country;
}
}
}
각종 ifelse 보는 이들의 눈이 어지럽다.php8에서는 Nullsafe로 개선해 볼 수 있습니다
$country = $session?->user?->getAddress()?->country;
7. 보다 합리적인 문자열과 숫자 비교
PHP8에서 숫자 문자열 비교( n)umeric string)의 경우 숫자로 비교됩니다. 숫자 문자열이 아닌 경우 숫자를 문자열로 변환하여 문자열별로 비교합니다
//PHP7
0 == 'foobar' // true
//PHP8
0 == 'foobar' // false
'개발 꿀팁 > PHP' 카테고리의 다른 글
Apache와 PHP 결합 (0) | 2022.07.16 |
---|---|
LAMP 환경 구축 및 PHP 사이트 배포 (0) | 2022.07.16 |
PHP에서 시스템 명령 실행 (disable_functions 바이패스) (0) | 2022.07.15 |
mariadb 간단한 소개와 PHP 환경 (0) | 2022.07.15 |
얘기 좀 하자~ PHP의 GC (0) | 2022.07.15 |