Skip to content

Analyzing PHP

公開日:

オンラインYouTube Liveで開催された『TechFeed Experts Night#24 〜 プログラミング言語をつくる・解析する ー 言語界隈をエキスパートが語る』で10分枠として発表しました。

Download PDF

スライドテキスト

Page 1

Analyzing PHP

pixiv Inc.
USAMI Kenta

2023-08-30

TechFeed Expert Night

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カンファレンス沖縄2023

Page 5

LLイベント

Page 6

PHPって
どんな言語?

Page 7

みなさんの想像する
PHPとは

Page 8

脆弱性 ゆるふわ 弱い型 動的

クソザコ 型なし 意味不明 弱い 自動変換 貧弱 Perlっぽい 適当
PHPについてのパブリックイメージ

Page 9

脆弱性 ゆるふわ 弱い型 動的

クソザコ 型なし 意味不明 弱い 自動変換 貧弱 Perlっぽい 適当
PHPについての認識は概ね間違い

Page 10

ソースコードで
見ると

Page 11

A

<!DOCTYPE html>
<html><head><title>Hello, PHP!</title></head>
<p>
<?php if (date('H') < 19): ?>
こんにちは

<?php else: ?> こんばんは

<?php endif; ?>
</p>
<p>今は<?= htmlspecialchars(date('H')) ?>時です</p>

Page 12

B

<?php require 'bootstrap.php';

$db = mysqli_connect();
$stmt = mysqli_prepare($db, 'SELECT * FROM books');
mysqli_stmt_execute($stmt); print '<h1>本の一覧</h1>';

print '<ul>';
foreach ($stmt as $s) {
print '<li>'; print $s->name; print '</li>';
}
print '</ul>';

Page 13

C

<?php declare(strict_types=1);

namespace Foo\Http\Controller;

class BooksController extends BaseController {
public function index() {
$books = Books::getAll();

$this->render(compact("books"));
}
}

Page 14

P H P の原作者
ラスマスかく語りき

Page 15

2007年 MySQL Conference

“We have things like protected properties. We have abstract methods. We have all this stuff that your computer science teacher told
you you should be using.
I don't care about this crap at all.”

–Rasmus Lerdorf
https://en.wikiquote.org/wiki/Rasmus_Lerdorf

Page 16

2007年 MySQL Conference

には プロパティも
“PHP protected
抽象メソッドもありますよ。計算機科学の
教授が「使え」と言ってるものは全部。

そんなことはクソ興味ないですけど

(tadsan )

–Rasmus Lerdorf

による超訳

Page 17

変数に$があって
Perlっぽくて

Page 18

C言語っぽい
関数と
-> があって

Page 19

雰囲気Javaっぽい オブジェクト指向で

Page 20

PHPは見る人の心を映す

Page 21

整理しましょう

Page 22

PHPは汎用プログラミング言語

  • PHPはHTTP(≒Webサービス)を言語レベルでサポートしている
    • ほかの言語ではCGIライブラリとしてサポートしている機能が組み込み
  • 各Webサーバとの連携はSAPI(Server API)として定義されている
    • どのサーバー上でもCGI風の動作をする
    • コマンドラインスクリプトとして実行するモード(CLI)もSAPIのひとつ

Page 23

Perl

use DBI;

$db = DBI->connect('...');
$stmt = $db->prepare('SELECT * FROM books');
$stmt->execute;
print '<h1>本の一覧</h1>'; print '<ul>';

for ($i = 0; $I < $sth->rows; $i++) {
@row = $sth->fetchrow_array;
print '<li>'; print $row[0]; print '</li>';
}
print '</ul>';

Page 24

B = CGIスタイル

<?php require 'bootstrap.php';

$db = mysqli_connect();
$stmt = mysqli_prepare($db, 'SELECT * FROM books');
mysqli_stmt_execute($stmt); print '<h1>本の一覧</h1>';

print '<ul>';
foreach ($stmt as $s) {
print '<li>'; print $s->name; print '</li>';
}
print '</ul>';

Page 25

現在でも動くCGI

Page 26

言語としてのPHP

  • よくあるC言語風の制御構文と標準関数をもったスクリプト言語
    • if, else, switch, while, for, goto
      • PHPのgotoは綺麗なgoto
  • 関数定義、クラス定義(class, interface, trait, enum)
  • クラスや関数の再定義(オープンクラス・モンキーパッチ)はできない

Page 27

PHPの実行フロー

  • いわゆるVM(仮想機械)型のインタプリタ
    • RubyをはじめPerl, Pythonなど現代的な言語は基本的にこれ
  • 字句解析→構文解析→オペコードコンパイル

Page 28

Page 29

仮想機械?

Page 30

Page 31

Page 32

I am CPU.

Page 33

つまり?

Page 34

自分のことをCPU だと思い込んだ象

Page 35

CPUの言葉でしゃべれ

Page 36

Zend Engine
オ ペ コ ー ド

opcode

Page 37

PHPはオペコードにコンパイルされる

<?php

echo 1; ECHO 1

Page 38

PHPはオペコードにコンパイルされる

<?php

echo 'foo'; ECHO 'foo'

Page 39

PHPはオペコードにコンパイルされる

<?php

print 'foo'; ECHO 'foo'

Page 40

PHPはオペコードにコンパイルされる

<?php

echo 1 + 2; ECHO 3

Page 41

PHPはオペコードにコンパイルされる

<?php
$a = 1; ASSIGN !0, 1


ADD ~2 !0, 2


echo $a + 2;

ECHO ~2

Page 42

opcodeでおk

<?php echo "foo";

ECHO 'foo'

Page 43

なんで
こんなことするの

Page 44

PHP
高度な構文解析が必要 な高級なシンタックス

Page 45

opcode
構文解析不要な
シンプルな命令セット

Page 46

分けて開発することで
最適化しやすくなる

Page 47

PHPと型宣言

  • いわゆる動的型付け(dynamic typing)のランタイム
  • 関数やプロパティ定義構文に型宣言があり、構文上で宣言されたものは
    実行時に確実にその型であることが保障される
    • ただし array などのコンテナは中に何が入っているか明示できない
  • 現状では変数には型がない (なんでも入る)

Page 48

PHPとDocComment型注釈

  • クラスや関数定義の真上のコメント内 /** ... */に型について注釈を書く
  • もちろんコメントなのでPHP実行中には解釈されないが、
    PhpStormのようなIDEや静的解析ツールなどが参照してくれる
  • array<Book> や array{name: string} のようにランタイムでは
    保障されない型が書ける

Page 49

静的解析しやすい特徴

  • クラスや関数が再定義されることは基本的にない
  • Java風のクラス継承(class, interface)
  • 関数呼び出しは全て () がつく、文末は必ず ;

Page 50

PHPの進化は 型宣言の進化

Page 51

いまやPHPは
静的型付きと言っても
過言ではない
(本当か…?)

Page 52

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

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

Page 53

スカラー型宣言(PHP7)

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

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

Page 54

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

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

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

Page 55

PHPDocの型注釈

(アノテーション)

/**
* @param int|float $a

あえて型宣言を省略する

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

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

Page 56

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

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

Page 57

LL言語としてのPHP vs エディタ

  • 2000年代のCGIやLL言語(Lightweight Language)という用語が
    よく使われていた頃は「重厚鈍重なIDEが必要な言語」のアンチテーゼとして
    シンプルなスクリプト言語とエディタが好まれていた (ように思う)
  • 時は流れ、Webアプリケーションは巨大になり、ファイルは増え、シンプルなエ
    ディタでは開発のオーバーヘッドが無視しがたくなってきた
  • PhpStorm(JetBrains社のIDE)が静的解析とインテリジェントな編集機能
    を提供してくれるようになった

Page 58

PHPと静的解析

  • PHP組み込みで提供されているのは php -l (syntax check) のみ
  • 「静的解析ツール」と呼ばれうるものは2000年代からあった
    • ドキュメント生成、コーディングスタイルのチェック
  • 2010年代後半になってPhpStormの普及を呼び水にして、
    型システムや変数スコープを正確に扱えるツールが開発され始めた

Page 59

PHP Static Analysis Tool

Page 60

PHPStanとは

  • 2016年から開発されているPHPの静的解析ツール
    • Ondřej Mirtesさんの個人プロジェクト、2021年からフルタイム開発
  • 開発当初は純粋な静的解析ではなく実行時リフレクションを用いることで
    高速な解析を実現していた
    • 現在は静的解析がデフォルトで、レガシープロジェクトに導入しやすくなった
  • その他のPHP静的解析ツールにはPsalm, Phan, Qodana(PhpStorm)

Page 61

PHPStanの提供する型

  • PHPの組み込み型、クラス名、インターフェイス名
  • 修飾型: non-empty-string, non-empty-array
  • ユニオン型: A|B
  • ジェネリクス: array<T>, ArrayObject<T>
  • 定数型: 123, "foo", Foo::BAR

Page 62

PHP処理系

  • ソースコード: https://github.com/php/php-src
  • 処理系のソースコードはC言語で書かれている(一部のみC++)
    • パーサーはYacc(Bison)で記述されている
    • 基礎知識は『Rubyソースコード完全解説』の知識が役に立つ
  • 議論はメーリングリストがメインだが、GitHub issueやPull Requestも
    受け付けてくれる

Page 63

PHPの開発体制

  • Request for Comments https://wiki.php.net/rfc
    • 言語機能の改廃提案と投票プロセス、リリース周期が明文化
  • 機能提案する人は仕様をまとめてMLで議論、実装も責任を持って用意する
  • PHP原作者のRasmus Lardorfは開発者としての1票しか行使しない
  • PHP 7.0(2015年)以降、11月末〜12月初頭にリリースが定着
    • 品質保障のためのfeature freeze、RC版なども定められた

Page 64

EmacsとPHP

  • 実はEmacsは標準でPHP編集機能を持っていない
  • サードパーティパッケージとしてPHP Modeを開発している
    • Emacsが提供するCc Modeという機能を基盤にしている
    • 「Cっぽい言語」をサポートするための巨大なフレームワークのようなもの
  • ほかの言語にある機能はキーワードを設定するだけ
    • ない機能は… 地道にサポートするしかない

Page 65

Emacs PHP Modeのサポート範囲

  • HTMLテンプレートのようなPHPコードはサポートしていない
    • 表示できない、まともにインデントできない
      • C言語族用のフレームワークがベースになっているため
    • 別のHTMLテンプレート用のモードを使うことを推奨

Page 66

php-modeの未解決issue

Page 67

最近のEmacs

  • Emacs 29でLSPクライアントとTree-sitterが統合されるようになった
    • 既にいくつかの言語についてTree-sitterベースの編集モードが同梱
  • Tree-sitterはエラー耐性のあるincremental parsing library
    • 言語ごとのtreesitter-xxxのようなライブラリをインストールする必要

Page 68

php-ts-mode

  • Emacs本体に同梱をされることを目標に開発中のパッケージ
  • tree-sitter-phpが提供してくれる構文木をベースに色付け・インデント
    • ライブラリをロードしたら簡単に提供できる… かと思ったが、
      それほど簡単ではなかった
  • 既存のphp-modeとの相互運用や基本的な問題を解決して、
    9月後半にリリースすることを目標に準備しています