PHP 8.2 有哪些新東西

發表時間: 2022-12-14 15:06:03
一劃 @ 220.128.125.133

PHP 8.2 在 2022/12/8 發布了,來看看有什麼新東西吧。

  1. Readonly Classes
  2. Deprecate dynamic properties
  3. New Rand Extension
  4. null, true and false as stanalone types
  5. Disjunctive Normal Form Types
  6. Constant in Trait
  7. Rdact parameters in back traces
  8. Fetch properties of enums in const expressions
  9. Return type changes for Date::createFormImmutable() and DateTime::createFormImmutable()
  10. utf8_encode() and utf8_decode() deprecations
  11. Locale-insensitive strtolower() and strtoupper()
  12. Signature chanages to serval SPL methods
  13. New n modifier in PCRE
  14. Deprecate ${} string interpolation
  15. New Functions and Clases
一劃 @ 220.128.125.133

Readonly Classes

PHP 8.1 時加入了物件唯讀屬性的方法,如果要全部屬性都是唯讀,在PHP 8.2可以直接在物件開頭宣告即可

PHP 8.1

class Post
{
    public function __construct(
        public string $string,
        public User|null $user,
        public string $body,
        public DateTimeInterface $publishedAt
    )
    {
    }
}

PHP 8.2

readonly public function __construct(
        public string $string,
        public User|null $user,
        public string $body,
        public DateTimeInterface $publishedAt
    )
    {
    }
』

Note: 如果你想擴展唯讀的物件,那子物件裡的屬性也一樣是唯讀。

一劃 @ 220.128.125.133

Deprecate dynamic properties

Dynamic Properties 在 8.2 棄用,只有在錯誤訊息設定打開 E_DEPRECATE 的設定才會出現,在 9.0 時則會直接噴錯(Throw ErrorException)。

class Post
{
    public string $title;
}

// …

$post->name = 'Name';

如果有用 get 及 set 在物件裡,就可以正常運行

class Post
{
    private array $properties = [];

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

    public function __get(string $name)
    {
        return $this->properties[$name];
    }
}

// …

$post->name = 'Name';

也可以在物件前宣告 #[AllowDynamicProperties], 就可以和之前一樣用 Dynamic Properties 了

#[AllowDynamicProperties]
class User
{
    public function __construct(
        readonly public string $name,
        public bool $valid = true,
        public string|null $password = null,
        public Status $status = Status::ONLINE
    )
    {

    }
}
一劃 @ 220.128.125.133

New Random Extension

新的亂數擴展應用

$rng = $is_production
    ? new RandomEngineSecure()
    : new RandomEngineMt19937();

$randomizer = new RandomRandomizer($rng);
$randomizer->shuffleArray(['abc', 'def', 'xyz']);
一劃 @ 220.128.125.133

null, true and false as stanalone types

null, true 及 false 可以做為獨立的型態來宣告。 之前 true 及 false 要用 Boolean 的型態來宣告,null 則是在 8.0 後一定要包含在 unino 中一起宣告才行,在 php8.2 之後都可以有其獨立的型態。

php8.1


    public function post(): Post|null
    {
        if (!empty($post)) {
            return $post;
        } else {
            return null;
        }
    }

    public function alwaysTrue(): Boolean
    {
        return true;
    }

php8.2


    public function alwaysTrue(): true
    {
        return true;
    }

    public function alwaysNull(): null
    {
        return null;
    }
一劃 @ 220.128.125.133

Disjunctive Normal Form Types 析取範式型態(DNF Type)

DNF types 可以讓我們組合聯集及交集的型態,當組合這兩個型態時,交集模型必須被括號包起來。

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

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

在這個範例中,(HasTitle&HasId)|null 就是 DNF Type

一劃 @ 220.128.125.133

Constant in Trait

可以在 trait 裡宣告常數了

trait HasUser
{
    public const NO_USER = 0;
    public const USER_INVALID = -1;
    public const USER_VALID = 1;

    public function checkUser()
    {
        if (empty($this->user)) {
            throw new Exception('No User', self::NO_USER);
        } else {
            return $this->user;
        }
    }
}

可以直接用物件來呼叫常數

class Post
{
    use HasUser;
    ...
}

Post::USER_VALID;
一劃 @ 220.128.125.133

Rdact parameters in back traces

回追蹤跡裡的密文參數

當我們在處理錯誤時,我們會追蹤所有參數及程序堆棧,有時會發送到第三方服務。但有些時候,一些比較敏感的參數我們不希望也一起送過去,例如密碼及其他服務的帳密。 PHP 8.2可以使用屬性標記這類的敏感參數,這樣就不用擔心會把這類訊息傳送到第三方了。

以上情形適用 php.ini 有以下設定時,通常已發行的產品版本這兩個值會是 On 及 0,也就是不回傳送錯誤發生時傳送的參數過去。

zend.exception_ignore_args = Off
end.exception_string_param_max_len = 15
    static public function login(User $user, string $name, #[SensitiveParameter] string $password)
    {
        if ($name == $user->name && $password == $user->password) {
            print 'Login ok';
        } else {
            throw new Exception('Login fail');
        }
    }

User::login($user,'Tsai Yi hua', 'abcc');

傳送回來的錯誤訊息時,password 變成了 Object(SensitiveParameterValue)

Fatal error: Uncaught Exception: Login fail in /data/tyh/projects/php8.2/pratice/app/User.php:20
Stack trace:
#0 /data/tyh/projects/php8.2/pratice/test.php(27): AppUser::login(Object(AppUser), 'Tsai Yi hua', Object(SensitiveParameterValue))
#1 {main}
  thrown in /data/tyh/projects/php8.2/pratice/app/User.php on line 20
一劃 @ 220.128.125.133

Fetch properties of enums in const expressions

常數設定時,允許直接提取列舉型態中的參數

Enums/Status.php

enum Status: string
{
    case ONLINE = 'online';
    case OFFLINE = 'offline';
}

Post.php

class Post 
{
    public const ONLINE = Status::ONLINE->name;
    public const OFFLINE = Status::OFFLINE?->name;
}
一劃 @ 220.128.125.133

Return type changes for Date::createFormImmutable() and DateTime::createFormImmutable()

Date::createFormImmutable() 及 DateTime::createFormImmutable() 的回傳型態變更

Before

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

In PHP 8.2

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

utf8_encode() and utf8_decode() deprecations

uft8_encdoe(), utf8_decode 在 PHP 8.2 棄用。 改用 mb_convert_encoding()

Locale-insensitive strtolower() and strtoupper()

strtolower() 及 strtoupper 拿掉對語言環境敏感的設定,也就是之後的大小寫轉換將和語言環境無關。 如果想要本地化的轉換,用 mb_strtolower 來替代。

Signature chanages to serval SPL methods

SplFileInfo::_bad_state_ex()
SplFileObject::getCsvControl()
SplFileObject::fflush()
SplFileObject::ftell()
SplFileObject::fgetc()
SplFileObject::fpassthru()
SplFileObject::hasChildren()
SplFileObject::getChildren()
一劃 @ 162.158.163.29

New n modifier in PCRE

PCRE: Perl-compitable Regular Expression
n = NO Auto Capture

preg_match('/^(.*)@(.*)/', 'abc@aabb.cc.dd', $match);
var_dump($match);

Output

array(3) {
  [0]=>
  string(14) "abc@aabb.cc.dd"
  [1]=>
  string(3) "abc"
  [2]=>
  string(10) "aabb.cc.dd"
}

加上 n 後

preg_match('/^(.*)@(.*)/n', 'abc@aabb.cc.dd', $match);
var_dump($match);

Output

array(1) {
  [0]=>
  string(14) "abc@aabb.cc.dd"
}

這個好處是在只想比較字串是否符合 PCRE 就好,不用額外輸出比對出來的結果,較省計算資源。

一劃 @ 220.128.125.133

Deprecate ${} string interpolation

${} 的變數取用方法棄用

"Hello ${world}";
Deprecated: Using ${} in strings is deprecated

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

New Functions and Classes

  • ini_parse_quantity
    • 解析PHP INI可辨識的數值。返回值為以 bytes 為單位的值。
       ini_parse_quantity('1M'); // 1048576

      當無法辨識時會列印出 warning 訊息,但還是傳回數值。

       ini_parse_quantity('232Kg');

      output

       Warning: Invalid quantity "232Kg", interpreting as "232g" for backwards compatibility in /data/tyh/projects/php8.2/pratice/test.php on line 35
       249108103168PHP Warning:  Invalid quantity "232Kg", interpreting as "232g" for backwards compatibility in /data/tyh/projects/php8.2/pratice/test.php on line 35
  • curl_upkeep
    • 當你使用 curl 有 keep-alive 需求時,可以用這個 function
       $handle = curl_init();
       curl_upkeep($handle);
       ...

      這個函式只有在 libcurl 是 7.62 以後才有用。還有連線目標如果有強制 keep-alive 時間的話,超過也無效。

  • openssl_cipher_key_length

    • 傳回 openssl 各種編碼方式所需的秘鑰長度(bytes)

       openssl_cipher_key_length("AES-128-GCM"); // 16
       openssl_cipher_key_length("AES-256-GCM"); // 32
      

      當編碼演算法不存在時則列印出 warning 訊息,並傳回 false

       openssl_cipher_key_length("NO-CHIPER-ALGORITHM");

      output

       Warning: openssl_cipher_key_length(): Unknown cipher algorithm in /data/tyh/projects/php8.2/pratice/test.php on line 35

回應文章