Skip to content

コードを自在に操るためのPHP文法入門

公開日:

大阪府大阪市北区グランフロント大阪で開催された『PHPカンファレンス関西2024』でレギュラートーク(40分)として発表しました。

Download PDF

スライドテキスト

Page 1

コードを自在に操るための
PHP文法入門

Introduction to PHP syntax for mastering code manipulation

pixiv Inc.
USAMI Kenta

PHPCon Kansai

2023-02-08 At Grand Front Osaka

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • ピクシブ株式会社 pixiv事業本部 Webエンジニアリングチーム PHPer
    • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
    • 最近はピクシブ百科事典(dic.pixiv.net)も開発しています
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にちょっとこだわりのある素人 (spcamp2010)

Page 3

emacs-php

Page 4

PHPカンファレンス関西2017

Page 5

PHPカンファレンス関西2018

Page 6

今回のお題

Page 7

世はまさに
静的解析時代!

Page 8

静的解析
プログラムの性質を
プログラムを実行せずに
検査する技術の総称

Page 9

2010年〜
PhpStormリリース

Page 10

Page 11

2018年〜
PHPStanの普及

Page 12

Page 13

PHPStanの特徴

  • PHPで書かれたオープンソースの静的解析ツール
    • ルールや型付けなどの拡張をPHPで柔軟に記述可能
  • 変数スコープや型推論が実装されており、プログラムを実行しなくても
    実行時の状態をかなり正確に推測できる
    • レガシーコードを解析するために実行時情報(ランタイムリフレクション)を
      利用することもできる

Page 14

PHPを正確に
理解したいと思った ことはありますか?

Page 15

PHPを正確に
理解したいと思った ことはありますか?

Page 16

正確じゃない理解
#とは

Page 17

ソースコードを
リファクタリングする
ことを考えましょう

Page 18

例えば:
クラス名を変更したい

Page 19

パッケージ全部ではなく 1クラスだけ移動したい

Hakone\Runner

Olympic\Athlete

Page 20

シェル芸で一発

$ find . -type f -name "*.php" -exec gsed -I \
's/Hakone\\\\Runner/Olympic\\\\Athlete/g' {} +

Page 21

シェル芸で一発

$ find . -type f -name "*.php" -exec gsed -I \
's/Hakone\\\\Runner/Olympic\\\\Athlete/g' {} +

Page 22

…そう簡単には
いきませんよね?

Page 23

なぜ単純に置換してはいけないのか

  • 単純置換でいける場合もある
    • クラス名が常にFQCN(完全修飾クラス名)で書かれているなら
  • PHPのクラス名は常にFQCNが書かれるわけではない
  • そもそも、ただの出力文字列としてコードに書かれたものと区別ができない
    • 例:クラスについてのHTMLドキュメントをPHPファイルに埋め込む

Page 24

PHP名前空間の
クラス名解決

Page 25

<?php
namespace Foo;

$now = new Date();
// Fatal error: Uncaught Error: Class "Foo\DateTime" not found

Page 26

クラス名の絶対参照

<?php
namespace Foo;

$now = new \Date();
// No errors.

Page 27

クラスのインポート

<?php
namespace Foo;
use Date;
$now = new Date();
// No errors.

Page 28

Page 29

Page 30

もっと簡単に

Page 31

Page 32

PhpStorm最高!

Page 33

PhpStorm最高!

Page 34

2024年、全PHPerは
リファクタリングの
全フローをPhpStorm に委ねるしかないのか?

Page 35

そうではない
(もちろんPhpStormも
優れた製品だが)

Page 36

ということで

Page 37

Rectorを使おう

Page 38

Page 39

Rectorとは

  • Tomas Votruba氏が開発する自動リファクタリングツール
    • ソースコード https://github.com/rectorphp/rector-src
  • Composerで簡単に導入できる
    • PHP 7.2以上で動作し、PHPStan以外への依存関係を持たない
  • 非常に数多くのルールを内蔵しているので、そのままで多くのユースケースに
    対応できる (PHPやPHPUnitのバージョンアップなど)

Page 40

Rectorの特徴

  • PHP-ParserとPHPStanをベースにカスタムルールを構築できる
    • 単純な構文木を扱えるだけでなく、PHPStanが分析する変数スコープや 型情報にアクセスできるため、(コードに適切な型がついているという前提に
      おいて)かなり信頼性の高いリファクタリングが可能
  • あくまで構文木を扱うツールなので、出力されるコードの細かいスタイルの 制御には対応していない (ほかのフォーマットツールや同作者のECSを併用)

Page 41

こうぶんき
構文木ってなんだ

Page 42

プログラムは
どうやって動くの?

Page 43

ソースコード

Page 44

字句解析(tokenize)

Page 45

Page 46

構文解析(parsing)

if条件式
if文 ==比較式

echo文

Page 47

トークン列

PHPはじまったな

if文はじまったな

条件式はじまったな

こいつの前後は==比較だな

条件式終了のお知らせ

ここからブロックだな

echoだな

文字列だな

; で echo \(^o^)/ オワタ

} で if文 \(^o^)/ オワタ

Page 48

Page 49

PHP-Parser

  • PHPの(元)コア開発者のNikita PopovによるPHP構文解析ライブラリ
    • PHPで書かれておりComposerで導入可能
    • PHPStan, Rector, PHPUnitなどはじめ多くのツールの基盤
  • 2024年1月8日にPHP-Parser 5.0がリリースされた
    • ただし現行のPHPStan, RectorはまだPHP-Parser 4.xを利用
    • PHPStanは2024年内にリリース予定の2.0で5.xに移行予定

Page 50

構文木 (4.x)

Page 51

構文解析(parsing)

if条件式
if文 ==比較式

echo文

Page 52

構文木 (4.x)

Page 53

構文木 (5.x)

Page 54

構文木 (syntax tree)

  • プログラムの構造を解析した結果を木構造にしたもの
  • PHPの場合は <?php foo(); bar(); のように ; 区切りでいくつも文を書
    けるので、トップレベル(一番外側)は配列 [] になっている
  • その内側に入っているものの一個一個のことを「ノード」と呼ぶ
    • PHPのクラスとして定義されている
  • PHP-Parserのノードの種類はGitHubで見るのがわかりやすい

Page 55

expression
= 式

Statement
= 文

Page 56

PHP構文での echoとprintの
違いは?

Page 57

式 vs 文

  • 式 (expressions) : 演算子や関数呼び出しなど組み合わせて書ける
  • 文 (statement) : 制御構造など、式の内側に書けないもの
    • if/switchのような制御構造やclass、functionの宣言文など
    • var_dump($v); 関数呼び出しや代入式だけの文は「式文」と呼ばれる

Page 58

Page 59

Page 60

式と文と式文

  • $a = 1 「代入文」と呼ばれがちだが、代入そのもの式
  • include_once や require_once も実は式ではなく文
  • PHP 8系では fn() や match () {} など式が使いやすくなった
    • PHP 7までは「throw文」だったが、PHP 8からは「throw式」になった
  • var_dump($v); 関数呼び出しや代入式だけの文は「式文」と呼ばれる

Page 61

PHP-Parser 4.x → 5.0

  • 実行環境要件としてPHP 7.4以上を要求
  • PHP 5.x専用パーサーを削除
  • 変な名前のクラスをわかりやすいようにリネーム

Page 62

PHP7 vs 8: トークナイズの違い

  • https://wiki.php.net/rfc/namespaced_names_as_token
    • PHP 8.0からnamespaceの一部に予約語を含められるようになった
    • その代りにトークンの間にスペース空けるのが許容されなくなった
  • PHP-Parser 5.0ではこのトークナイズの結果が反映される

Page 63

token_get_all()の違い

Page 64

PHP 7.xで動いてたコード

Page 65

PHP 8.xで動くコード

Page 66

スライドここまで

Page 67

隣の世界でも
構文解析時代の到来

Page 68

Page 69

Page 70