너의 개발은/PHP

PHP: PHP 8 기능 정리 및 요약

PHP 8

2015년 php7 이 등장한 이후 5년만에 php8 이 시동을 걸었다. 아직 베타 버전이지만, 어느정도 기능은 확정되었고 문법적으로 큰 변화가 있었다. 페이스북의 HHVM(Hiphop Virtual Machine)이 그랬던 것 처럼 JIT(Just In Time) 컴파일러를 도입하여 속도는 크게 향상되었다. 물론 HHVM 보다도 속도는 이미 PHP 7.x 에서 넘어섰기 때문에 이 둘에 대한 비교는 하지 않아도 된다. 이 포스트에서는 대체로 문법적인 부분들을 살펴본다.

 

각 부분에 대한 포스트를 자세하게 작성할 필요는 없겠지만, 속성(a.k.a 어노테이션)같은 경우에는 완전 신 기능이라 이후에 구현이 온전히 되었을 때는 알아봐야 할 지도 모르겠다.

 

https://www.inflearn.com/course/php8-new-features

 

PHP 8, 새로운 기능 살펴보기 - 인프런

5년 만에 등장한 PHP 8의 새로운 기능들을 간단하게 살펴봅니다. PHP 8의 신기능이 궁금하다면 한 번 들어보세요! 초급 프로그래밍 언어 PHP 온라인 강의 새롭게 등장한 최신 PHP 8의 기능을 가볍게 ��

www.inflearn.com

https://github.com/pronist/php8-feature-examples

 

pronist/php8-feature-examples

This Repo contains PHP 8 feature Examples. Contribute to pronist/php8-feature-examples development by creating an account on GitHub.

github.com

Trailing Comma 파라매터 목록

Trailing Comma(뭐라고 해석해야?) 파라매터 목록을 허용한다. 단순한 변화이지만, 코딩 스타일 표준에 따라 유동적으로 사용할 수 있다.

class A
{
    public function __construct(
        string $a,
        string $b,
    ) {}
}

혼합 타입

자료형을 명시해줄 수 있는데, 여기에 여러 타입을 같이 적어줄 수는 없었으나, 이제는 함수나 메서드, 리턴 타입에 다중 타입을 명시해줄 수 있다.

function foo(int|string $bar): int|string {}
https://wiki.php.net/rfc/union_types_v2

타입 확장

여기서 말하는 확장은 슈퍼/서브 클래스를 말하는 것이 아니라, 파라매터가 리턴 타입에 다른 타입도 받을 수 있도록 확장하는 것을 말한다.

interface AInterface
{
    public function foo(int $bar): int|string;
}

class A implements AInterface
{
    public function foo(int|string $bar): int|string
    {
        return $bar;
    }
}

슈퍼/서브 클래스에서 타입 축소

이번에는 타입을 축소할 수 있다. 슈퍼/서브 클래스 간에는 서브 클래스를 부모 클래스로 교환할 수 있기에 가능한 일이다.

interface BInterface
{
    public function foo(B|C $bar): B|C;
}

class B {}
class C extends B {}

class D implements BInterface
{
    public function foo(B $bar): B
    {
        return new B();
    }
}

NULL

null 타입을 핸들링하기 위해서는 두 가지 방법을 따른다. 먼저 첫 번째는 유니온 타입을 사용하는 것이고, 두 번째는 타입 앞에 ? 를 사용하는 것이다.

function foo(null|string $bar): void {}
// function foo(?string $bar): void {}

mixed, static 타입 추가

static, mixed 타입이 추가되었는데, 나도 가끔씩 실수로 mixed 타입을 쓸 때가 있었다. mixed 타입은 본래 문서상에는 존재했으나 in Code 에서는 사용할 수 없는 것다.

mixed

mixed 타입은 여러 타입을 반환하거나 받을 수 있다. 타입스크립트의 any 같은 느낌이라고나 할까.

function foo(mixed $bar)
{
    var_dump($bar);
}

foo('Hello, world');
foo(fn () => 'Hello, world');
https://wiki.php.net/rfc/mixed_type_v2

static

static 타입은 에서도 보았듯, static 키워드를 사용하여 늦은 정적 바인딩을 할 때 유용할 것이다.

class A
{
    public function getClass(): static
    {
        return new static();
    }
}

class B extends A
{
}

var_dump((new B())->getClass()); // -> B
https://wiki.php.net/rfc/static_return_type

이 타입은 또한 클래스 프로퍼티함수/메서드 파라매터가 될 수 없다. 더군다나 프로퍼티로 쓸 때 정적 프로퍼티를 의미하는 건지 타입을 의미하는 건지 알 수 없기 때문인데, 정적 프로퍼티이면서 정적 타입이라면 static static 으로 쓰는건 어떤가?

 

따라서 아래의 문법은 허용하지 않는다.

class C extends A
{
    // Is this an untyped static property,
    // or an instance property of type static?
    public static $a;

    // FUNCTION PARAMS
    public function foo(static $a): void
    {
    }
}

self

여담으로 static 타입은 self 타입의 서브 타입이다. 따라서 self리턴 타입으로 쓰면 static 타입도 반환할 수 있지만, static 타입만 명시하면 self 는 반환할 수 없다.

class A 
{
    public function getClass(): self
    {
        return $this;
    }
}

class B extends A {}

var_dump((new B())->getClass()); // -> B

nullsafe 연산자

객체에서 어떤 메서드나 프로퍼티에 접근할 때, 객체가 null 인 경우 에러를 던졌었으나, nullsafe 연산자를 사용하면 이것을 방지하고 객체가 null 인경우, 말 그대로 null 을 리턴한다. 동적타입을 가졌고, 런타임 동안에 null 이 될 수도 있기 때문에 이를 방지할 수 있다는 것은 아주 좋은 기능이라고 생각한다.

$class = null;
var_dump($class?->getMessage()); // -> NULL
https://wiki.php.net/rfc/nullsafe_operator

명명된 파라매터

파이썬이나 다른 언어처럼 키워드 파라매터를 사용할 수 있다. 코드의 가독성이 한결 상승할 것은 물론 기본값과 섞여있을 때 빛을 발휘하게 될 예정이다. 굳이 기본값에 있는 내용에 값을 채운다거나 파라매터의 순서를 신경쓰면서 함수를 만들 필요가 없어진다. 

function foo(string $bar): void 
{
}

foo(bar: 'Hello, world');
https://wiki.php.net/rfc/named_params

속성(a.k.a 어노테이션)

어노테이션이 추가된다. 따라서 자바처럼 어노테이션 단위로 기능을 분리하여 나타낼 수 있게된다. PHP 8.0 Beta4 버전에서는 파스 에러를 뱉는데, 그 이유는 아직 문법적으로 명확하게 확정이 되지 않았기 때문인 듯 보인다.

 

https://wiki.php.net/rfc/shorter_attribute_syntax_change

 

PHP: rfc:shorter_attribute_syntax_change

PHP RFC: Shorter Attribute Syntax Change Introduction With the continued discussion over the currently selected attribute syntax @@ from the Shorter Attribute Syntax RFC we want to revisit the syntax choice once and for all, so that we can be as sure as po

wiki.php.net

RFC(Request for Comments)를 보면 여전히 표현의 선택을 고민하고 있다. 따라서 속성은 추가는 되겠지만 표현의 방법에 있어서 어떠한 것이 선택될지는 아직 모른다. 후보로는 #[], @@ 등이 있는 것 같다. 다른 언어에서 쓰고 있는 @는 이미 에러와 관련된 연산자로 예약이 되어 있다.

class PhpAttribute
{
    public const int IS_REPEATABLE = ((1 << 10));
}
 
<<PhpAttribute(self::IS_REPEATABLE)>>
class Route
{
}
 
class HomepageController
{
    <<Route("/")>>
    <<Route("/homepage")>>
    public function indexAction()
    {
    }
}
https://wiki.php.net/rfc/attribute_amendments

match 표현식

match 표현식은 switch ~ case 문을 조금 더 보기좋게 표현한다. 다른 언어에서는 본 적이 없으나 이러한 표현식은 구문을 단축하고 가독성을 높히는데 도움을 준다. 참고로 break 키워드는 사용되지 않는다. 또한 swtich ~ case 문과는 다르게 값을 리턴한다는 특징이 있다. 이 표현식은 단일 라인만 사용이 가능하다.

$errorCode = 400;

function getErrorCode() {
    return 400;
}

// switch ($errorCode) {
//     case getErrorCode():
//         $msg = 'Bad Reqeust';
//         break;
//     default:
//         $msg = 'Hello, world';
// }

$msg = match ($errorCode) {
    getErrorCode() => 'Bad Request',
    200, 201, 202, 203 => 'OK',
    default => 'Hello, world'
};

var_dump($msg); // -> Bad Request
https://wiki.php.net/rfc/match_expression_v2

UnhandledMatchError

매치가 올바르게 이루어지지 않은 경우 매치에 대한 UnhandledMatchError 가 발생한다.

// UnhandledMatchError
match (500) {
    200, 201, 202, 203 => 'OK'
};

생성자

생성자를 사용할 때도 단축해서 사용할 수 있도록 변경되었다. 자바스크립트처럼 된 듯하다. 생성자 파라매터를 줄 때 프로퍼티까지 같이 선언할 수 있는 것이다. 참고로 타입은 필수가 아니며, 기본값을 넣어줄 수도 있고, 일반적인 생명자 파라매터를 만들어 줄 수도 있다.

// class MyClass 
// {
//     public string $message;

//     public function __construct(string $message) 
//     {
//         $this->$message = $message;
//     }
// }

class MyClass
{
    public function __construct(public string $message) 
    {
    }
}
https://wiki.php.net/rfc/constructor_promotion

함수에서 예외 반환하기

이전까지는 할 수 없었지만, 이제부터는 예외를 반환할 수 있게되었다. 이는 내가 가끔 실수로 적었다고 수정하는 것들인데 합법적으로 할 수 있게 되었다.

function foo() 
{
    return throw new Exception();
}

$foo = fn () => throw new Exception();
https://wiki.php.net/rfc/throw_expression

WeakMap

WeakMapWeakReference 처럼 객체의 참조만을 가지고 있어서 키로 가지고 있는 객체를 메모리에서 해제할 경우 WeakMap 객체 내부에서도 날라가게 된다. Cache 로 사용하는 것이 가장 무난한 예제다.

$weakMap = new WeakMap();

$class = new stdClass();
$weakMap[$class] = 'Hello, world';

/*
    [0]=>
    array(2) {
        ["key"]=>
        object(stdClass)#2 (0) {
        }
        ["value"]=>
        string(12) "Hello, world"
    }
}
*/
var_dump($weakMap);

unset($class);
/*
    object(WeakMap)#1 (0) {
    }
*/
var_dump($weakMap);
https://wiki.php.net/rfc/weak_maps

오브젝트에서 ::class 사용하기

본래는 클래스 자체를 대상으로 할 수만 있었던 것을, 이제 오브젝트에서도 ::class 를 사용할 수 있게된다.

$class = new stdClass();
var_dump($class::class); // -> stdClass
https://wiki.php.net/rfc/class_name_literal_on_object

try ~ catch 에서 변수 생략하기

try ~ catch 를 사용할 때 본래 catch 블럭에 변수를 넣어야 했습니다만, 생략할 수 있도록 바뀌었습니다.

try {
    throw new Exception();
} catch (Exception) {
}
https://wiki.php.net/rfc/non-capturing_catches

Stringable 인터페이스

Stringable 인터페이스가 추가되었습니다. 해당 인터페이스는 별거없고, 그냥 매직메서드 __toString() 을 통해 객체가 스트링으로 표현될 수 있냐에 따른 것입니다.

class MyClass implements Stringable 
{
    public function __toString(): string
    {
        return 'Hello, world';
    }
}

echo new MyClass(); // -> Hello, world
https://wiki.php.net/rfc/stringable

참고 자료

참고 자료에는 내가 포스트에 적지 않은 내용이나 자잘한 변화가 나열되어 있다. 새로운 내장 함수의 추가나 작은 변화들을 더 살펴보고 싶다면 아래의 문서를 참고하길. 물론 공식 문서는 내용이 너무 길어서 이 글을 썼다. 영어가 싫진 않지만 길어지니까 싫어진다. RFC(Request for Comments) 문서를 볼 때는 PHP 8 섹션에서 찾아보면 된다.

 

https://github.com/php/php-src/blob/master/UPGRADING

 

php/php-src

The PHP Interpreter. Contribute to php/php-src development by creating an account on GitHub.

github.com

https://wiki.php.net/rfc

 

PHP: rfc

This page gives an overview of the current RFCs for PHP. To create a new RFC, see How To Create an RFC. Note: An RFC is effectively “owned” by the person that created it. If you want to make changes, get permission from the creator. If no agreement can

wiki.php.net

https://stitcher.io/blog/new-in-php-8

 

What's new in PHP 8 - stitcher.io

All new features, deprecations, speed and performance improvements in PHP 8

stitcher.io

 

'너의 개발은 > PHP' 카테고리의 다른 글

PHP: PHP 8 기능 정리 및 요약  (1) 2020.09.23
PHP: 게시판  (0) 2020.09.11
PHP 7+ 핸드북 및 문서 정리  (2) 2020.09.03
PHP: 회원가입과 로그인  (0) 2020.09.02
PHP: PSR(PHP Standard Recommendation)  (0) 2020.08.15
PHP: 의존성 관리자 — Composer  (0) 2020.08.14