Page 1
配列、ジェネリクス、
PHPで書けない型
公開補訂版
Arrays, Generics, and Types that cannot be type-declared.
pixiv Inc.
USAMI Kenta
2021.10.03
公開日:
by USAMI Kenta @tadsan
にオンラインのYouTube Liveで開催された『PHPカンファレンス2021』でレギュラーセッション(30分)として発表しました。
配列、ジェネリクス、
PHPで書けない型
公開補訂版
Arrays, Generics, and Types that cannot be type-declared.
pixiv Inc.
USAMI Kenta
2021.10.03
お前誰よ
tadsanのあれこれが読める場所
WEB+DB PRESS総集編
Software Design 11月号
今回のお題
プロポーザル
いきなりですが
問題です
値をそのまま返す関数
function id(mixed $value): mixed {
return $value;
}
値をそのまま返す関数
PhpStormとかで
メソッド名補完がきく
$date = new DateTimeImmutable();
$date->diff(
値をそのまま返す関数
PhpStormとかで
メソッド名補完が
き…かない
$date = new DateTimeImmutable();
id($date)->diff(
値をそのまま返す関数
なんでも受け取って
function id(mixed $value): mixed {
return $value;
なんでも返す
}
本日の目標は
こういうときに怯えず
型を付けることです
個々の静的解析ツール
導入方法などは
今回は扱いません
ただし最新のPhpStorm 2021.2では静的解析ツー ルを導入しなくてもすんな
り動くと思います
これまでのあらすじ
PHPカンファレンス2016
PHPカンファレンス福岡2019
PHP勉強会@東京
(2020年2月)
PHPカンファレンス沖縄2021
型とPHPの歴史
型についておさらい
型とは何か
PHPは動的言語
型チェックは実行時まで遅延する
<?php
$a : array
$b : int
$a = [];
そもそも
$b = 1;
計算できない
echo $a + $b;
PHPの型宣言の特徴
型チェックは実行時まで遅延する
返り値でintに
パラメータ
変換する
mixed
<?php
1 : int
$toint = fn($n): int => $n;
0 : int
var_dump($toint('1'));
var_dump($toint((int)''));
返り値で厳密な
var_dump($toint(''));
チェック
漸進的型付けで動的言語を型検査する
型がついていない関数
function add($a, $b) {
return $a + $b;
}
型宣言すればいい?
int + intって
本当にintなの?
function add(int $a, int $b):int {
return $a + $b;
}
floatにすればいい?
ひとつの解決策では
あるが… 不必要に¸oat
を強制するのか
function add(float $a, float $b):float {
return $a + $b;
}
PHPDocの型注釈
(アノテーション)
/**
* @param int|float $a
あえて型宣言を省略する
* @param int|float $b
* @return int|float
*/
function add($a, $b) {
return $a + $b;
}
Union型宣言(PHP8.0)
function add(
int|float $a,
int|float $b
): int|float {
return $a + $b;
}
かくしてPHPは PHPDocなんか 書かなくても良い
平和な世界になりました
HAPPY END?
😇
ほんとうにそうか?
Bookクラスは著者を持つ
上司
「共著を想定できてる?」
class Book
{
function __construct(
private Author $author
) {
// ...
}
}
Bookの著者は複数居る
arrayにすることで
複数であることを表現
class Book
{
function __construct(
private array $authors
) {
Authorクラスの
// ...
情報が減ってる…
}
}
著者一覧を出力したい
Book::$authors : array 中身が何かわからない!
class Book
{
function printAuthors($fp): void {
foreach ($this->authors as $author) {
fwrite($fp, $author->getName());
}
Authorクラスの
}
メソッドを補完できない
}
Bookの著者は複数居る
arrayにすることで
複数であることを表現
class Book
{
function __construct(
private array $authors
) {
Authorクラスの
// ...
情報が減ってる…
}
}
著者は複数居る
PHPDocの復活
class Book
{
function __construct(
/** @var array<Author> */
private array $authors
) {
// ...
}
著者一覧を出力したい
Book::$authors :
array<Author>
class Book
{
function printAuthors($fp): void {
foreach ($this->authors as $author) {
fwrite($fp, $author->getName());
}
Authorクラスの
}
メソッドが補完できる
}
この事例からわかること
配列はひとつ!じゃない!!
list<int>
array<int,string>
array{id:int, name:string}
[
['id' => 123, 'name' => '野比のび太'],
['id' => 234, 'name' => '源静香'],
]
list<array{id:int, name:string}>
配列の記法
型パラメータ
array<int>
array<Author>
いろんなものが書ける
再掲: 値をそのまま返す関数
function id(mixed $value): mixed {
return $value;
}
再掲: 値をそのまま返す関数
/**
* @template T
* @phpstan-param T $value
* @phpstan-return T
*/
function id(mixed $value): mixed {
return $value;
}
値をそのまま返す関数
PhpStormとかで
メソッド名補完が きくようになった
$date = new DateTimeImmutable();
id($date)->diff(
これを活用する
配列の先頭要素をとる関数
/
**
* @template T
* @param array<T> $XS
* @param T $default
* @return T
*/
function first(array $xs, mixed $default): mixed {
f u n c ftoiroen afcih r(s$tx(sa rarsa y$ x$)x sr,e tsutrrni n$gx ;$default): mixed {
rreettuurrnn $$vdaelfuaeu;lt;
}}
配列の先頭要素をとる関数
/**
* @template T
* @param array<T> $xs
* @param T $default
* @return T
*/
function first(array $xs, mixed $default): mixed {
foreach ($xs as $x) return $x;
return $default;
配列の先頭要素を受け取る
PhpStormとかで
メソッド名補完がきく
を返す関数
// list<DateTimeImmutable>
$dates = get_dates();
$first = first($dates, new DateTimeImmutable);
$first->diff(
これを活用する
kane.php
フォント
FOT-ハミング Std (M)
BIZ UDPゴシック (Regular)
Courier (Regular)