こういうのに時間を取られるとヽ(・ω・)/ズコーってなるのでメモっておく。
対象読者
autoloaderの使われていないようなレガシーなシステムでの罠のお話しです。そんなに古臭いシステムを触らない場合は読んでも得るものはありません。
新規で作るシステムは一般的にrequire_onceを使うよりオートローダを使うほうがよいでしょう。記述も簡潔だし、PHPはPSRに従っていれば恩恵が得られるエコシステムになっているためです。
呼び出し側ファイルに定義されているクラスをrequireされるファイルのクラスが利用している場合
使われてないように見えるクラスがあるよー
Backpack.phpでは、冒頭でServalクラスをrequireしています。
このファイルはBackpackクラスとUnyaクラスが同居しています。Unyaクラスは Unya::nya()
という静的メソッドをもっていますね。一見するとこのUnyaクラスは利用されていないように見えます。
<?php
require_once __DIR__ . '/Serval.php';
class Backpack {
public function echi(){
$serval = new Serval();
$serval->berk();
}
}
class Unya { // 使われていない?
static public function nya(){
echo 'unya nya nya nya nya nya nya' . PHP_EOL;
}
}
$backpack = new Backpack();
$backpack->echi();
requireされた側に定義がないよー?
requireされた側のServal.phpです。何もrequireしていませんが、静的メソッドを呼んでいます。
<?php
class Serval {
public function berk(){
Unya::nya(); // 定義はどこに?
}
}
UnyaクラスはBackpack.phpで定義されていました。
まさか そんな 🍌
動くんですか?
$ php Backpack.php
unya nya nya nya nya nya nya
はい(例の顔)
何故動くのか
Backpack.phpは冒頭でServal.phpをrequireしています。
require_once
によってServal.phpが読み込まれることで、$serval->berk()
が実行される際にはすべてのクラスが揃っており、エラーなく実行できます。
一見利用されていないようにみえたUnyaクラスはこのようにして利用されていました。
(このような抽象度で)動くことを理解するのは別に難しくはないのですが、はじめてみた時にびっくりしたのでメモ。
教訓:クラスを利用する側が利用するファイルをrequireするようにして下さい
ついで単一のファイルに複数のクラスを定義するのもなるべく避けて下さい。