PHP8時代にarray型と向き合う

公開日:

オンラインYouTube Liveで開催された『PHPerKaigi petit - PHP8.1リリース祝賀会』で発表枠(20分)として発表しました。

Download PDF

スライドテキスト

Page 1

PHP8時代にarray型と向き合う

Faced with array type in the PHP 8.x era

pixiv Inc.
USAMI Kenta

Tue Dec 21 2021 09:00:00 GMT+0900 (Japan Standard Time)

PHPerKaigi petit - PHP8.1リリース祝賀会

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 エンジニア
    • 最近はピクシブ百科事典(dic.pixiv.net)を開発しています (PSR-15!)
  • Emacs Lisper, PHPer
    • Emacs PHP Modeを開発しています (2017年-)
  • PHPカンファレンス実行委員、PHPerKaigi コアスタッフ

Page 3

tadsanのあれこれが読める場所

  • https://tadsan.fanbox.cc/
  • https://scrapbox.io/php/
  • https://www.phper.ninja/
  • https://zenn.dev/tadsan
  • https://qiita.com/tadsan
  • https://github.com/bag2php

Page 4

WEB+DB PRESS総集編

Page 5

Software Design 11月号

Page 6

前回までのあらすじ

Page 7

最後のPHP勉強会

(2020年)

Page 8

PHPカンファレンス沖縄2021

Page 9

PHPカンファレンス2021

Page 10

なんかいろいろ 話してきました

Page 11

PHPの進化は 型宣言の進化

Page 12

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

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

Page 13

スカラー型宣言(PHP7)

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

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

Page 14

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

ひとつの解決策では
あるが… 不必要にfloat
を強制するのか

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

Page 15

PHPDocの型注釈

(アノテーション)

/**
* @param int|float $a

あえて型宣言を省略する

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

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

Page 16

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

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

Page 17

クラスの型も
PHP7→8で進化

Page 18

著者を持つBookクラス

class Book

{

/** @var Author */

private $author

public function __construct(Author $author) {

$this->author = $author;
}
}


Page 19

PHP 7.4でプロパティ型宣言

class Book

{

/** @var Author */

private Author $author

public function __construct(Author $author) {

$this->author = $author;
}
}


Page 20

コンストラクタプロモーション

(PHP8)

class Book

{

function __construct(
private Author $author

) {

何も書かなくてもプロパティに代入される

// 

}
}


Page 21

readonlyプロパティ

(PHP8.1)

class Book

{

function __construct(
public readonly Author $author

) {

何も書かなくてもプロパティに代入される

// 

}
}


Page 22

かくしてPHP
PHPDocの型が
不要な世界に

Page 23

Bookクラスは著者を持つ

上司

class Book


「共著を想定できてる?」

{

function __construct(
private Author $author

) {

何も書かなくてもプロパティに代入される

// 

}
}


Page 24

Bookクラスは複数の著者を持つ

arrayにすることで

class Book


複数であることを表現

{

function __construct(
private array $authors

) {

何も書かなくてもプロパティに代入される

// 


Authorクラスの

}

情報が減ってる…

}


Page 25

著者一覧を出力したい

Book::$authors : array 中身が何かわからない!

class Book

{

function printAuthors($fp): void {
foreach ($this->authors as $author) {
 fwrite($fp, $author->getName());

}


Authorクラスの

}

メソッドを補完できない

}


Page 26

何か大事なものを
失ってしまった
気がする

Page 27

今回は配列に絞って
話します

Page 28

PHPの配列は万能

Page 29

PHPの配列はなんでもできる

Page 30

PHPマニュアルより引用

Page 31

PHPの配列は
ハッシュテーブル

Page 32

JavaScript/Rubyの場合

Page 33

PHPの場合

Page 34

何が違うのか

Page 35

他の言語における配列(array)

  • C言語における配列はメモリ上の連続した領域に並べたもの
    (ポインタとかアドレスとかの概念が絡んでくる)
    • インデックスは0が始点、長さ(値の数)は最初に決める
  • JavaScriptやRubyでの配列は複数の値を格納できるオブジェクト
    • インデックスは0が始点、動的に拡張される
    • 長さ以上のインデックスに代入されると、間の値はnull的な値で埋められる

Page 36

PHPの配列はハッシュテーブル

  • PHPの配列は基本的にハッシュテーブルというデータ構造
    • 任意の int または string の値をキーにできる
    • 長さ以上に代入しても間がnullで埋められることはない
  • 連続していない前提の配列を特に「連想配列」と呼ぶ
    • 英語ではassociative array (略してassoc)などと呼ばれる
  • PHPだけではなくLuaという言語も似た仕様

Page 37

PHP7の内部実装から学ぶ性能改善テクニック

Page 38

PHP7から内部的に「配列」が入った

  • 2015年リリースのPHP 7.0ではデータ構造に大きく手が入った
    • $a = [1, 2, 3] のような値は(C言語的な意味)の配列として保持される
    • 既存の配列に $a['str'] = 'val' のように追加するとき
      ハッシュテーブルに詰め替えられる

Page 39

連想配列 vs リスト

  • PHPでは区別されないが、たとえば値をjson_encode()する時など
    連想配列と連続した値を厳密に比較したいことはありうる
    • JSONでは歯抜けの値があると [] ではなく {} になってしまう
    • array_9lter() の結果など
  • array_values() で歯抜けのない配列に変換できる
  • PHP 8.1で array_is_list() で判定できる

Page 40

array_is_list()について

  • PHP 8.1で追加された関数
  • 従来は 0 から順にforeachして歯抜けがないかチェックする必要があった
  • 静的解析ツール(PHPStan, Psalmなど)ではPHPDocに
    array<int,string> の代りに list<string>と書ける
    • 最近のPhpStormでは(検査は不十分だが)認識してくれる
    • Intelephenseは未実装

Page 41

Authorsはどうなれば
よかったのか

Page 42

Bookクラスは複数の著者を持つ

class Book

{

function __construct(


private array $authors

) {

何も書かなくてもプロパティに代入される

// 

}
}


Page 43

PHPDocの帰還

class Book

{

function __construct(

/** @var list<Authors> */
private array $authors

) {

何も書かなくてもプロパティに代入される

// 

}
}


Page 44

配列はひとつ!じゃない!!

list<int>

array<int,string>

  • ユーザIDがならんだリスト [123, 456]
  • ユーザIDと名前の対応表 [123 => '野比のび太', 234 => '源静香']
  • ユーザを表す構造体 ['id' => 123, 'name' => '野比のび太']
  • ユーザを表す構造体がならんだリスト

array{id:int, name:string}

[
['id' => 123, 'name' => '野比のび太'],
['id' => 234, 'name' => '源静香'],

]

list<array{id:int, name:string}>