PHP 8.2 có gì mới

PHP 8.2 có gì mới

PHP 8.2 sẽ được phát hành vào ngày 24 tháng 11 năm 2022. Trong bài đăng này, chúng ta sẽ tìm hiểu các tính năng, cải tiến hiệu suất, thay đổi và không dùng nữa trong lần phát hành này nhé.

#Readonly classes - Lớp chỉ đọc (rfc)

Ở phiên bản php 8.1 chúng ta có Readonly properties ở phiên bản 8.2 thêm cú pháp để làm cho tất cả các thuộc tính của class chỉ được đọc cùng một lúc. Thay vì viết code thế này:

class Post
{
    public function __construct(
        public readonly string $title, 
        public readonly Author $author,
        public readonly string $body,
        public readonly DateTime $publishedAt,
    ) {}
}

Giờ chúng ta có thể viết:

readonly class Post
{
    public function __construct(
        public string $title, 
        public Author $author,
        public string $body,
        public DateTime $publishedAt,
    ) {}
}

Về mặt chức năng, việc tạo một lớp chỉ đọc hoàn toàn giống như việc tạo mọi thuộc tính chỉ đọc; nhưng nó cũng sẽ ngăn các thuộc tính động được thêm vào một lớp:

$post = new Post(/* … */);

$post->unknown = 'wrong';

Uncaught Error: Cannot create dynamic property Post::$unknown

Lưu ý rằng bạn chỉ có thể mở rộng từ các readonly classes  nếu lớp con cũng là readonly class.

#Deprecate dynamic properties - Không chấp nhận thuộc tính động (rfc)

Tôi muốn nói rằng đây là một thay đổi để tốt hơn, nhưng nó sẽ ảnh hưởng một chút. Thuộc tính động không được chấp nhận trong PHP 8.2 và sẽ tạo ra lỗi ErrorException trong PHP 9.0:

class Post
{
    public string $title;
}

// …

$post->name = 'Name';

Các class implement các method __get__set vẫn sẽ hoạt động như bình thường:

class Post
{
    private array $properties = [];
    
    public function __set(string $name, mixed $value): void
    {
        $this->properties[$name] = $value;
    }
}

// …

$post->name = 'Name';

#New random extension (rfc)

PHP 8.2 bổ sung một trình tạo số ngẫu nhiên mới để khắc phục nhiều vấn đề với phần trước: nó hoạt động hiệu quả hơn, an toàn hơn, dễ bảo trì hơn và không dựa vào trạng thái toàn cục; loại bỏ một loạt lỗi khó phát hiện khi sử dụng các hàm ngẫu nhiên của PHP.

Có một lớp mới được gọi là Randomizer, chấp nhận một randomizer engine

$rng = $is_production
    ? new Random\Engine\Secure()
    : new Random\Engine\Mt19937(1234);
 
$randomizer = new Random\Randomizer($rng);
$randomizer->shuffleString('foobar');

#nulltrue, and false as standalone types (rfc)

PHP 8.2 bổ sung thêm ba kiểu mới là null, true và false có thể được coi là các loại hợp lệ. Các ví dụ phổ biến là các hàm tích hợp sẵn của PHP, trong đó false được sử dụng làm kiểu trả về khi xảy ra lỗi. Ví dụ trong file_get_contents:

file_get_contents(/* … */): string|false

Trước PHP 8.2, bạn đã có thể sử dụng false cùng với các kiểu khác như một liên hợp; nhưng bây giờ nó cũng có thể được sử dụng như một loại độc lập:

function alwaysFalse(): false
{
    return false;
}

Tương tự với null và true

#Disjunctive Normal Form Types (rfc)

Các loại DNF cho phép chúng ta kết hợp union (|)intersection (&)types, tuân theo một quy tắc nghiêm ngặt: intersectiontypes phải được nhóm với dấu ngoặc. Trong thực tế, nó trông như thế này:

function generateSlug((HasTitle&HasId)|null $post) 
{
    if ($post === null) {
        return '';
    }

    return 
        strtolower($post->getTitle()) 
        . $post->getId();
}

Trong trường hợp này, (HasTitle&HasId)|null là DNF type.

#Constants in traits - Hàm số trong trait (rfc)

Bây giờ bạn có thể sử dụng hằng số trong các trait:

trait Foo 
{
    public const CONSTANT = 1;
 
    public function bar(): int 
    {
        return self::CONSTANT;
    }
}

Bạn sẽ không thể truy cập hằng số thông qua tên của trait, từ bên ngoài trait hoặc từ bên trong nó.

trait Foo 
{
    public const CONSTANT = 1;
 
    public function bar(): int 
    {
        // không thể truy cập từ bên trong!
        return Foo::CONSTANT;
    }
}

// không thể truy cập từ bên ngoài!
Foo::CONSTANT;

Tuy nhiên, bạn có thể truy cập hằng số thông qua class sử dụng trait, với điều kiện là nó công khai:

class MyClass
{
    use Foo;
}

MyClass::CONSTANT; // 1

#Redact parameters in back traces (rfc)

Khi code chạy trên production thường xảy ra lỗi, chúng ta có thể dùng các dịch vụ theo dõi để phát hiện điều này và gửi chúng cho dev sửa. Thường khi lỗi phát sinh sẽ có stack traces để có thể dò tìm lỗi, nhưng nó cũng đi kèm với những thông tin nhạy cảm như biến môi trường, mật khẩu hoặc tên người dùng.

PHP 8.2 cho phép bạn đánh dấu các "tham số nhạy cảm" như vậy bằng một thuộc tính, do đó bạn không cần phải lo lắng về việc chúng được liệt kê trong stack traces khi có sự cố. Đây là một ví dụ từ RFC:

function login(
    string $user,
    #[\SensitiveParameter] string $password
) {
    // …
    
    throw new Exception('Error');
}
 
login('root', 'root');
 
Fatal error: Uncaught Exception: Error in login.php:8
Stack trace:
#0 login.php(11): login('root', Object(SensitiveParameterValue))
#1 {main}
  thrown in login.php on line 8

#Fetch properties of enums in const expressions (rfc)

Thông tin từ RFC:

This RFC proposes to allow the use of ->/?-> to fetch properties of enums in constant expressions. The primary motivation for this change is to allow fetching the name and value properties in places where enum objects aren't allowed, like array keys

Điều đó có nghĩa là đoạn code bên dưới giờ sẽ đúng:

enum A: string 
{
    case B = 'B';
    
    const C = [self::B->value => self::B];
}

#Thay đổi kiểu trả về của DateTime::createFromImmutable()DateTimeImmutable::createFromMutable() (breaking)

Trước đó các phương thức đó sẽ trông như thế này:

DateTime::createFromImmutable(): DateTime
DateTimeImmutable::createFromMutable(): DateTimeImmutable

Trong PHP 8.2, kiểu trả về của các phương thức đó sẽ thay đổi như thế này

DateTime::createFromImmutable(): static
DateTimeImmutable::createFromMutable(): static

#Không dùng utf8_encode() và utf8_decode() nữa (rfc)

Với PHP 8.2, khi sử dụng utf8_encode() hoặc utf8_decode() sẽ bắn ra deprecation notices:

Deprecated: Function utf8_encode() is deprecated
Deprecated: Function utf8_decode() is deprecated

Giải pháp thay thế ư? RFC đề xuất sử dụng phương thức mb_convert_encoding()

#strtolower() và strtoupper() không còn hỗ trợ locale character nữa(breaking, rfc)

Cả strtolower() và strtoupper() sẽ không còn hổ trợ locale character nữa. Bạn có thể sử dụng use mb_strtolower() nếu muốn hỗ trợ..

#Signature changes to several SPL methods (breaking)

Several methods of SPL classes have been changed to properly enforce their correct type signature:

SplFileInfo::_bad_state_ex()
SplFileObject::getCsvControl()
SplFileObject::fflush()
SplFileObject::ftell()
SplFileObject::fgetc()
SplFileObject::fpassthru()
SplFileObject::hasChildren()
SplFileObject::getChildren()

#New n modifier in PCRE (upgrading)

Giờ bạn có thể sử dụng modifier n (NO_AUTO_CAPTURE) trong các function pcre*

#ODBC username and password escaping (breaking)

Từ hướng dẫn UPGRADING :

The ODBC extension now escapes the username and password for the case when both a connection string and username/password are passed, and the string must be appended to.

Tương tự với PDO_ODBC.

#Không dùng cú pháp nội suy chuỗi ${} nữa (rfc)

PHP có nhiều các để đặt biến bên trong chuỗi. RFC này không dùng hai cách trong số đó nữa, nếu dùng sẽ có Deprecated notices:

"Hello ${world}";
Deprecated: Using ${} in strings is deprecated
 
"Hello ${(world)}";
Deprecated: Using ${} (variable variables) in strings is deprecated

Những các nội suy chuỗi này thì vẫn hoạt động bình thường:

"Hello {$world}";
"Hello $world";

#Deprecate partially supported callables (rfc)

Another change, although one with a slightly smaller impact, is that partially supported callables are now deprecated as well. Partially supported callables are callables which can be called using call_user_func($callable), but not by calling $callable() directly. The list of these kinds of callables is rather short, by the way:

"self::method"
"parent::method"
"static::method"
["self", "method"]
["parent", "method"]
["static", "method"]
["Foo", "Bar::method"]
[new Foo, "Bar::method"]

The reason for doing this? It's a step in the right direction towards being able to use callable for typed properties. Nikita explains it very well in the RFC:

all of these callables are context-dependent. The method that "self::method" refers to depends on which class the call or callability check is performed from. In practice, this usually also holds for the last two cases, when used in the form of [new Foo, "parent::method"].

Reducing the context-dependence of callables is the secondary goal of this RFC. After this RFC, the only scope-dependence still left is method visibility: "Foo::bar" may be visible in one scope, but not another. If callables were to be limited to public methods in the future (while private methods would have to use first-class callables or Closure::fromCallable() to be made scope-independent), then the callable type would become well-defined and could be used as a property type. However, changes to visibility handling are not proposed as part of this RFC.

#Nguồn

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