hysryt / wiki

https://hysryt.github.io/wiki/
0 stars 0 forks source link

PHP7.4 #127

Open hysryt opened 4 years ago

hysryt commented 4 years ago
docker run --rm -p 8080:80 -v "$PWD/public":/var/www/html php:rc-apache
hysryt commented 4 years ago

引数の型の反変性と戻り値の型の共変性のサポート

オーバーライドする際、以下のコードが書けるようになった。

<?php
class A {}
class B extends A {}

class Producer {
    public function method(B $b): A {}
}
class ChildProducer extends Producer {
    public function method(A $a): B {}
}
?>

引数の型の反変性

反変性とは、最初に指定された型よりも一般的な (弱い派生の) 型を使用できることを言う。 メソッドの引数の型に、元のメソッドの引数の型の基底クラスを指定しても良い性質。 派生クラス型で受け取れるものは基底クラス型でも受け取れると考えるとわかりやすい。

B b = new B();   // Bで受け取れるなら
A a = new B();   // Aでも受け取れる

今までは Warning が出ていた。

戻り値の型の共変性

共変性とは、最初に指定された型よりも強い派生型を使用できることを言う。 メソッドの戻り値の型に、元のメソッドの戻り値の型のサブクラスを指定しても良い性質。 基底クラス型を返すなら派生クラス型を返しても良い(受け取る方は基底クラス型で受け取る)と考えるとわかりやすい。

今までは Fatal error が出ていた。

hysryt commented 4 years ago

型付きプロパティ

クラスのプロパティに型をつけられるようになった。

<?php
class User {
    public int $id;
    public string $name;
}

型と違う値を入れると Fatal error が出る。

<?php
class User {
    public int $id = 'a';
    public string $name;
}

// Fatal error: Default value for property of type int can only be int in /var/www/html/index.php on line 3
hysryt commented 4 years ago

Null合体代入演算子

$array['key'] ??= 'value';

$array['key'] が Null の場合、'value' が代入される。

以下と同じ。

if (!isset($array['key'])) {
    $array['key'] = 'value';
}
hysryt commented 4 years ago

アロー関数

無名関数を定義する際のシンタックスシュガー

<?php
$factor = 10;
$f = fn($n) => $n * $factor;
$nums = array_map($f, [1, 2, 3, 4]);

use が不要で、関数内で使用している変数が関数の外側にある場合、定義時に値渡しされる。 関数の処理部分には1行しか書くことができないため、2行以上書く必要がある場合は今まで通りの構文で書く必要がある。

<?php
$factor = 10;
$f = function($n) use ($factor) {
  echo 'hello';
  return $n * $factor;
}
$nums = array_map($f, [1, 2, 3, 4]);

この構文の追加に伴い、グローバルスコープで fn という名前の関数を定義するとシンタックスエラーが出るようになった。

<?php
function fn() {}

// Parse error: syntax error, unexpected 'fn' (T_FN), expecting '(' in /var/www/html/index.php on line 2
hysryt commented 4 years ago

配列内でのスプレッド演算子

配列Aの中で配列Bにスプレッド演算子を使うことで、配列Aのなかに配列Bの要素を展開(アンパック)できる。 添字配列であればarray_merge が不要になった。 連想配列に使用することはできない。

<?php
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
// ['banana', 'orange', 'apple', 'pear', 'watermelon'];

ジェネレーター関数に対して使用することも可能。

function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        yield $i;
    }
}

$a = [...gen_one_to_three()];
// [1, 2, 3];
hysryt commented 4 years ago

数値リテラルパラメータ

数値リテラルを書く際に _ を入れられるようになり、見やすくできるようになった。 _ を入れられるのは数値間のみ。(先頭に入れると定数として扱われてしまい、末尾に入れるとパースエラーとなる)

$num = 1_000_000;
$color = 0xFF_FF_FF;
hysryt commented 4 years ago

弱い参照

オブジェクトの破棄を妨げない参照を持てるようになった。 キャッシュを作るときなどに使える。 弱い参照は7.3まで拡張機能によって提供されていたが、7.4からPHP本体側で用意するらしい。


<?php
$obj = new stdClass;
$weakref = WeakReference::create($obj);
var_dump($weakref->get());  // object(stdClass)#1 (0) { }
unset($obj);
var_dump($weakref->get());  // NULL
hysryt commented 4 years ago

__toStringメソッド内で例外が投げられるように

__toString() はインスタンスが文字列に変換される際の動作を記述できるマジックメソッド。

<?php
class A {
  function __toString() {
    throw new Exception();
  }
}

$a = new A();

echo $a;
// PHP7.3
// Fatal error: Method A::__toString() must not throw an exception, caught Exception: in /var/www/html/index.php on line 0
// PHP7.4
// Fatal error: Uncaught Exception in /var/www/html/index.php:5 Stack trace: #0 /var/www/html/index.php(10): A->__toString() #1 {main} thrown in /var/www/html/index.php on line 5
hysryt commented 4 years ago

CURLFile がストリームラッパーをサポート

CURLFileは cURL関数を使ってファイルをアップロードする際に必要になるクラスとのこと。 使用したことがないため詳しくは不明。

hysryt commented 4 years ago

FILTER_VALIDATE_FLOAT フィルタにオプション追加

min_rangeオプションとmax_rangeオプションが追加された

<?php
var_dump(filter_var(1.4, FILTER_VALIDATE_FLOAT, [
  'options' => [
    'min_range' => 1.5
  ]
]));

// PHP7.3
// float(1.4)
// PHP7.4
// bool(false)

PHP7.3以前だと素通りしてしまうため注意。

hysryt commented 4 years ago

FFI

C言語で定義された関数や変数、データ構造をPHPから使用できるようにする拡張機能、とのこと。 FFIと言う用語自体はPHP独自のものではなく、広く使われているもの。 https://ja.wikipedia.org/wiki/Foreign_function_interface

PHPからTensorFlowの機能を使うプロジェクトもある模様 https://github.com/dstogov/php-tensorflow

参考 https://column.prime-strategy.co.jp/archives/column_3179#outline__3

<?php
$ffi = FFI::cdef("double sin(double x);","libm.so.6");
var_dump($ffi->sin(1));  // float(0.8414709848079)

Dockerfile

FROM php:rc-apache
RUN apt-get update && apt-get install -y libffi-dev \
    && docker-php-ext-install -j$(nproc) ffi \
    && echo ffi.enable=true >> /usr/local/etc/php/conf.d/docker-php-ext-ffi.ini
hysryt commented 4 years ago

mb_str_split() が追加

str_split() のマルチバイト文字版。 str_split() は文字列を1文字ごとに区切って配列にする関数。

<?php
var_dump(mb_str_split("あいうえお"));
// array(5) { [0]=> string(3) "あ" [1]=> string(3) "い" [2]=> string(3) "う" [3]=> string(3) "え" [4]=> string(3) "お" }
hysryt commented 4 years ago

プリロード

OPcacheにプリロードという機能が追加されて、なんか知らんけど速くなるらしい。

hysryt commented 4 years ago

その他

・ preg_replace_callback() と preg_replace_callback_array() に引数追加 ・PDOで、DSNにユーザー名(username)とパスワード(password)が設定可能に ・PDOで、SQL内に??とすると?が使用できるように ・PDO_OCI で getColumnMeta() が使用可能に ・PDO_SQLiteで、ステートメントがデータに変更を加えるかどうかをチェック可能に ・strip_tags()で許可するタグを配列で指定可能に ・serialize と unserialize マジックメソッド追加 ・Serializable は将来的に削除 ・array_merge() と array_merge_recursive() が引数なしでも実行可能に ・

hysryt commented 4 years ago

Password Hashing Registry

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

前置き

password_*() 関数を使用することで、標準化されたパスワードハッシュ化メカニズムをアプリケーションに持ち込むことができます。 bcrypt は常にサポートされます。 libargon が使用可能な場合であれば、argon2i とargon2id もサポートされます。

libargon が必要という条件はphp-srcを綺麗に保っているLinux ディストリビューションにとって悪化要因となります。 ユーザーによっては必要のないライブラリを持つことになります。 この提案ではHash拡張機能の php_hash_register_algo() API のような Password Hashing Registryの導入により、これを改善することを求めています。

つまり拡張機能からパスワードハッシュ化アルゴリズムを追加できるようになったということ?

提案

内部API

  struct php_password_algo {
    const char* name; // Symbolic name of the algorithm, e.g. "argon2id"
    zend_string* (*hash)(const zend_string* password, zend_array* options);
    zend_bool (*verify)(const zend_string* password, const zend_string* hash);
    zend_bool (*needs_rehash)(const zend_string* hash, zend_array *options);
    int (*get_info)(zval *return_value, const zend_string* hash);
    zend_bool (*valid)(const zend_string* hash);
  };
  PHPAPI int php_password_algo_register(const char* ident, const php_password_algo*);
  PHPAPI void php_password_algo_unregister(const char* ident);
  PHPAPI const php_password_algo* php_password_algo_default();
  PHPAPI zend_string *php_password_algo_extract_ident(const zend_string* hash);
  PHPAPI const php_password_algo* php_password_algo_find(const zend_string* ident);
  PHPAPI const php_password_algo* php_password_algo_get_named(const zend_string* name);
  PHPAPI php_password_algo* php_password_algo_identify(const zend_string* hash);

アルゴリズム実装を提供する拡張機能は php_password_algo 構造体を作成し、MINIT(moudule initialization?)内でphp_password_algo_register を呼び出します。

ユーザースペースAPI

アルゴリズムリストを返す password_algos() が追加されました。

hysryt commented 4 years ago

Sodium拡張機能が password_*() に argon2i(d) の実装を提供

https://wiki.php.net/rfc/sodium.argon.hash

前置き

libargon 無しでPHPコアをビルドした場合、password_*() は argon2i および argon2id をサポートしません。しかし、Password Hash Registry によりロード時の動的なパスワードハッシュアルゴリズムの追加が可能となり、また、libsodium が argon2i と argon2id の実装を持っているため、バックフィルの実装が可能となりました。

自前でPHPをビルドする場合はコンパイル前に libargon をインストールすればいいため、さほど問題ではありません。