Skip to content

ジェネリクスを自分のものにする

公開日:

オンラインZoomウェビナーで開催された『Qiita Night~PHP~』でライトニングトーク(10分)として発表しました。

Download PDF

スライドテキスト

Page 1

ジェネリクスを
自分のものにする

Getting Started with Generic Programming

pixiv Inc.
USAMI Kenta

2022-01-25

Qiita Night ~PHP~

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 エンジニア
    • 最近はピクシブ百科事典(dic.pixiv.net)を開発しています
    • すごい肩書の発表者が多いですが僕はヒラのPHPerです (IC?)
  • Emacs Lisper, PHPer
    • Emacs PHP Modeを開発しています (2017年-)

Page 3

Page 4

Page 5

静的解析してますか?

Page 6

Page 7

Page 8

ジェネリクスの
話をしよう

Page 9

ジェネリックプログラミング - Wikipedia(2022-05-02T17:30:09の版)より引用

Page 10

データ型に
依存しない…?

Page 11

抽象的かつ 汎用的…?

Page 12

Page 13

まず基本的な
静的型の話

Page 14

静的型付け

(statically typing)

  • 静的 = 実行しなくても型がわかる状態 (反対語は動的 = プログラム実行)
  • 型宣言 (コードに型を書く)
    • 現状のPHPではパラメータとプロパティに型宣言できる
    • PHPは処理系が実行時の型を保障してくれる (口約束ではない!)
  • 型推論 (文字で型を書かなくても空気を読んでくれる)
    • $a = count($array) のとき $a の型は常に int
    • $b = 1 + 2 の結果は int(3)

Page 15

型付けの具体例を 見ていきましょう

Page 16

まずはジェネリクスと
あまり関係ない例

Page 17

型がついていない関数(PHP5)

型宣言なし = mixed

function add($a, $b) {
return $a + $b;
}

Page 18

スカラー型宣言(PHP7)

int + intって
本当にintなの?

function add(int $a, int $b): int {
return $a + $b;
}

Page 19

広い値をとるにはfloatが必要

ひとつの解決策では
あるが… 不必要に(cid:190)oat
を強制するのか

function add(float $a, float $b): float {
return $a + $b;
}

Page 20

PHPDocの型注釈

(アノテーション)

/**
* @param int|float $a

あえて型宣言を省略する

* @param int|float $b
* @return int|float
*/

function add($a, $b) {
return $a + $b;
}

Page 21

ユニオン型宣言 (PHP8.0)

function add(int|float $a, int|float $b): int|float {
return $a + $b;
}

Page 22

基本的な型宣言

  • PHPの言語として記述できる静的な型宣言は大まかに3種類
    • 具体的な型
      • int, (cid:190)oat, string, bool, array, DateTimeInterface, ...
    • 複合的な型
      • A|B, int|false, ?DateTime, ArrayAccess&Traversable ...
    • 型定義をしない (または mixed)

Page 23

かくして世界は
型の炎に包まれた

Page 24

だが型なしは
死滅していなかった

Page 25

別の例を
考えてみましょう

Page 26

配列の先頭要素を返す関数

function first(array $a, mixed $default): mixed {
return $a[0] ?? $default;
}

$vの型は何?

$v = first([0, 1, 2], 'default');

Page 27

int専用関数をつくろう

function first_int(array $a): ?int {
return $a[0] ?? null;
}

$v = first_int([0, 1, 2]) ?? 'default';

Page 28

string専用関数をつくろう

function first_string(array $a): ?string
return $a[0] ?? null;
}

$v = first_string(['a', 'b', 'c']) ?? 'default';

Page 29

DateTime専用関数をつくろう

function first_DateTime(array $a): ?DateTime
return $a[0] ?? null;
}

$v = first_DataTime([]) ?? 'default';

Page 30

関数量産は
めんどくさい

Page 31

ユニオン型は問題解決しない

function first(array $a): int|string|DateTime|null {
return $a[0] ?? $default;

なんでDateTimeとか

}

出てくるの?

$v = first([0, 1, 2], 'default');

Page 32

?DateTimeとか
int|falseくらいなら
問題ない

Page 33

それを補うのが

PHPDoc

Page 34

PHPDocタグ
いくついえるかな

Page 35

@param

Page 36

@return

Page 37

@var

Page 38

@template

Page 39

…なにそれ?

Page 40

@template は型変数

/**
* @template TValue
* @template TDefault
* @param array<TValue> $a * @param TDefault $default * @return TValue|TDefault
*/
function first(array $a, mixed $default) {

Page 41

Page 42

Page 43

やっていきましょう

Page 44

Page 45

Page 46

いまは内部型表現の
制約でシンプルな 型しか付かないが

Page 47

そのうち
万病に効くようになる

Page 48

Page 49

Page 50

テンプレートは
クラスにも書ける

Page 51

Page 52

ジェネレータでも
使える

Page 53

Page 54

コレクションも
簡単に定義できる

Page 55

Page 56

tagged union

Page 57

Page 58

モナド

Page 59

Page 60

実際難しいことは

(そんなに)
やってない

Page 61

試行錯誤したことが
ない技術が難しいのは
あたりまえ

Page 62

PHPStanは
Webでこねこね
試行錯誤がやりやすい

Page 63

PHPStan
完全にマスターしよう

Page 64

Page 65

今回はひたすら
実例を詰め込んで
話しました

Page 66

ジェネリクスの知識は
なくても
PHPStanは使える

Page 67

Page 68

宣伝

Page 69

Page 70

Page 71

会社で実用しよう

PHPStan