はじめに
PHP の SPL(Standard PHP Library)は、データ構造・反復子・ファイル操作・例外・オートロードなど、多彩な機能を提供するコアライブラリです。しかし「今の環境で SPL がどんなクラスを提供しているのか」を一覧で確認したいとき、どうすればよいでしょうか。
spl_classes() はまさにその答えとなる関数で、現在の PHP 環境で利用可能な SPL のクラスとインターフェースをすべて連想配列で返します。開発環境の調査・ドキュメント生成・動的なクラス存在チェックなど、さまざまな場面で役立ちます。
関数の基本情報
| 項目 | 内容 |
|---|---|
| 関数名 | spl_classes() |
| 利用可能バージョン | PHP 5.0以降 |
| 所属 | SPL(Standard PHP Library) |
| 戻り値 | array(クラス名 → クラス名 の連想配列) |
| 拡張機能 | SPL(デフォルトで有効) |
シグネチャ
spl_classes(): array
パラメータ
なし。
戻り値の形式
[
'AppendIterator' => 'AppendIterator',
'ArrayIterator' => 'ArrayIterator',
'ArrayObject' => 'ArrayObject',
// ...(キーと値が同じ文字列)
]
特徴: キーと値が同じ文字列です。
array_keys()でもarray_values()でも同じクラス名リストが得られます。
SPL クラスのカテゴリ
spl_classes() が返すクラスは大きく以下のカテゴリに分類されます。
| カテゴリ | 代表的なクラス |
|---|---|
| データ構造 | SplStack, SplQueue, SplHeap, SplMinHeap, SplMaxHeap, SplPriorityQueue, SplDoublyLinkedList, SplFixedArray |
| 反復子(Iterator) | ArrayIterator, DirectoryIterator, RecursiveDirectoryIterator, RecursiveIteratorIterator, FilterIterator, LimitIterator, AppendIterator など |
| ファイル操作 | SplFileInfo, SplFileObject, SplTempFileObject |
| オブジェクトストレージ | SplObjectStorage |
| 例外 | LogicException, RuntimeException, InvalidArgumentException, OutOfRangeException など |
| インターフェース | Countable, Iterator, IteratorAggregate, ArrayAccess, Serializable など |
| その他 | ArrayObject, SplObserver, SplSubject |
実践サンプル集(PHP 8.x対応)
サンプル1:基本的な一覧取得と表示
<?php
declare(strict_types=1);
$classes = spl_classes();
echo "SPL クラス・インターフェース総数: " . count($classes) . "\n\n";
// 先頭10件を表示
$preview = array_slice($classes, 0, 10);
foreach ($preview as $name) {
$type = interface_exists($name) ? 'interface'
: (class_exists($name) ? 'class'
: 'unknown');
echo sprintf(" %-40s [%s]\n", $name, $type);
}
echo " ...\n";
実行結果:
SPL クラス・インターフェース総数: 57
AppendIterator [class]
ArrayIterator [class]
ArrayObject [class]
BadFunctionCallException [class]
BadMethodCallException [class]
CachingIterator [class]
CallbackFilterIterator [class]
Countable [interface]
DirectoryIterator [class]
DomainException [class]
...
解説: interface_exists() と class_exists() を組み合わせることで、各エントリがクラスかインターフェースかを判別できます。
サンプル2:カテゴリ別に分類して表示
SPL クラスをカテゴリに整理して一覧表示する診断ツールです。
<?php
declare(strict_types=1);
/**
* SPLクラスをカテゴリ別に分類する
*
* @return array<string, list<string>>
*/
function categorizeSplClasses(): array
{
$all = array_keys(spl_classes());
sort($all);
$categories = [
'データ構造' => [],
'反復子' => [],
'ファイル操作' => [],
'例外' => [],
'インターフェース' => [],
'オブザーバー' => [],
'その他' => [],
];
foreach ($all as $name) {
if (str_starts_with($name, 'Spl') && (
str_contains($name, 'Stack') ||
str_contains($name, 'Queue') ||
str_contains($name, 'Heap') ||
str_contains($name, 'Priority') ||
str_contains($name, 'Linked') ||
str_contains($name, 'Fixed')
)) {
$categories['データ構造'][] = $name;
} elseif (str_ends_with($name, 'Iterator') || str_ends_with($name, 'IteratorIterator')) {
$categories['反復子'][] = $name;
} elseif (str_starts_with($name, 'SplFile')) {
$categories['ファイル操作'][] = $name;
} elseif (str_ends_with($name, 'Exception')) {
$categories['例外'][] = $name;
} elseif (interface_exists($name)) {
$categories['インターフェース'][] = $name;
} elseif (str_contains($name, 'Observer') || str_contains($name, 'Subject')) {
$categories['オブザーバー'][] = $name;
} else {
$categories['その他'][] = $name;
}
}
return array_filter($categories, fn($v) => !empty($v));
}
$categorized = categorizeSplClasses();
foreach ($categorized as $category => $names) {
echo "\n【{$category}】({$count = count($names)}件)\n";
foreach ($names as $name) {
$type = interface_exists($name) ? 'I' : 'C'; // I=Interface, C=Class
echo " [{$type}] {$name}\n";
}
}
$total = array_sum(array_map('count', $categorized));
echo "\n合計: {$total}件\n";
実行結果:
【データ構造】(7件)
[C] SplDoublyLinkedList
[C] SplFixedArray
[C] SplMaxHeap
[C] SplMinHeap
[C] SplPriorityQueue
[C] SplQueue
[C] SplStack
【反復子】(21件)
[C] AppendIterator
[C] ArrayIterator
[C] CachingIterator
...
【ファイル操作】(3件)
[C] SplFileInfo
[C] SplFileObject
[C] SplTempFileObject
【例外】(13件)
[C] BadFunctionCallException
[C] BadMethodCallException
...
【インターフェース】(6件)
[I] ArrayAccess
[I] Countable
[I] Iterator
[I] IteratorAggregate
[I] OuterIterator
[I] RecursiveIterator
...
合計: 57件
解説: 名前パターン・interface_exists() を組み合わせることで、spl_classes() の返り値を実用的なカテゴリへ整理できます。
サンプル3:環境差分の検出
PHP バージョンや設定の違いによる SPL クラスの差異を検出するパターンです。
<?php
declare(strict_types=1);
/**
* 2つの環境のSPLクラス一覧を比較する
*
* @param list<string> $env1
* @param list<string> $env2
*/
function diffSplClasses(array $env1, array $env2, string $label1 = 'Env1', string $label2 = 'Env2'): void
{
$onlyIn1 = array_diff($env1, $env2);
$onlyIn2 = array_diff($env2, $env1);
$common = array_intersect($env1, $env2);
echo "=== SPL クラス差分レポート ===\n";
echo "共通: " . count($common) . "件\n";
echo "{$label1} のみ: " . count($onlyIn1) . "件\n";
echo "{$label2} のみ: " . count($onlyIn2) . "件\n";
if (!empty($onlyIn1)) {
echo "\n{$label1} にあって {$label2} にないクラス:\n";
foreach (array_values($onlyIn1) as $name) {
echo " - {$name}\n";
}
}
if (!empty($onlyIn2)) {
echo "\n{$label2} にあって {$label1} にないクラス:\n";
foreach (array_values($onlyIn2) as $name) {
echo " + {$name}\n";
}
}
}
// 現在の環境のSPLクラス
$current = array_keys(spl_classes());
// 例:以前の環境で記録したスナップショット(PHP 8.0相当の想定)
$snapshot = [
'AppendIterator', 'ArrayIterator', 'ArrayObject',
'BadFunctionCallException', 'BadMethodCallException',
'CachingIterator', 'CallbackFilterIterator', 'Countable',
'DirectoryIterator', 'DomainException',
'EmptyIterator', 'FilesystemIterator', 'FilterIterator',
'GlobIterator', 'InfiniteIterator', 'InvalidArgumentException',
'IteratorIterator', 'LengthException', 'LimitIterator',
'LogicException', 'MultipleIterator', 'NoRewindIterator',
'OutOfBoundsException', 'OutOfRangeException', 'OuterIterator',
'OverflowException', 'ParentIterator', 'RangeException',
'RecursiveArrayIterator', 'RecursiveCachingIterator',
'RecursiveCallbackFilterIterator', 'RecursiveDirectoryIterator',
'RecursiveFilterIterator', 'RecursiveIterator',
'RecursiveIteratorIterator', 'RecursiveRegexIterator',
'RecursiveTreeIterator', 'RegexIterator',
'RuntimeException', 'SeekableIterator',
'SplDoublyLinkedList', 'SplFileInfo', 'SplFileObject',
'SplFixedArray', 'SplHeap', 'SplMaxHeap', 'SplMinHeap',
'SplObjectStorage', 'SplObserver', 'SplPriorityQueue',
'SplQueue', 'SplStack', 'SplSubject', 'SplTempFileObject',
'UnderflowException', 'UnexpectedValueException',
];
diffSplClasses($snapshot, $current, 'スナップショット', '現在');
実行結果(差分がある場合):
=== SPL クラス差分レポート ===
共通: 55件
スナップショット のみ: 1件
現在 のみ: 2件
スナップショット にあって 現在 にないクラス:
- SplHeap
現在 にあって スナップショット にないクラス:
+ ArrayAccess
+ IteratorAggregate
解説: CI/CD パイプラインや複数サーバー環境での SPL クラス一致チェックに使えます。デプロイ前後の差分確認や PHP バージョンアップ時の影響調査にも有効です。
サンプル4:クラスの詳細情報をリフレクションで収集
spl_classes() と ReflectionClass を組み合わせてクラス情報を詳細調査するパターンです。
<?php
declare(strict_types=1);
/**
* SPLクラスの詳細情報を収集する
*
* @return list<array{name: string, type: string, abstract: bool, parents: list<string>, interfaces: list<string>, methods: int}>
*/
function analyzeSplClasses(): array
{
$result = [];
foreach (array_keys(spl_classes()) as $name) {
try {
$ref = new ReflectionClass($name);
} catch (ReflectionException) {
continue;
}
$type = $ref->isInterface() ? 'interface'
: ($ref->isTrait() ? 'trait'
: 'class');
$parents = [];
$parent = $ref->getParentClass();
while ($parent !== false) {
$parents[] = $parent->getName();
$parent = $parent->getParentClass();
}
$result[] = [
'name' => $name,
'type' => $type,
'abstract' => $ref->isAbstract(),
'final' => $ref->isFinal(),
'parents' => $parents,
'interfaces' => array_values(array_keys($ref->getInterfaceNames())),
'methods' => count($ref->getMethods(ReflectionMethod::IS_PUBLIC)),
];
}
return $result;
}
$info = analyzeSplClasses();
// メソッド数上位5件を表示
usort($info, fn($a, $b) => $b['methods'] - $a['methods']);
echo "=== メソッド数ランキング TOP 10 ===\n";
foreach (array_slice($info, 0, 10) as $entry) {
$flags = implode(' ', array_filter([
$entry['abstract'] ? '[abstract]' : '',
$entry['final'] ? '[final]' : '',
]));
printf(
" %-40s %3d メソッド %s\n",
$entry['name'] . " ({$entry['type']})",
$entry['methods'],
$flags
);
}
// 抽象クラス一覧
echo "\n=== 抽象クラス ===\n";
$abstracts = array_filter($info, fn($e) => $e['abstract'] && $e['type'] === 'class');
foreach ($abstracts as $entry) {
echo " {$entry['name']}\n";
}
// インターフェース一覧
echo "\n=== インターフェース ===\n";
$interfaces = array_filter($info, fn($e) => $e['type'] === 'interface');
foreach ($interfaces as $entry) {
echo " {$entry['name']}\n";
}
実行結果(抜粋):
=== メソッド数ランキング TOP 10 ===
SplFileObject (class) 44 メソッド
RecursiveDirectoryIterator (class) 29 メソッド
DirectoryIterator (class) 28 メソッド
SplFixedArray (class) 16 メソッド
ArrayObject (class) 15 メソッド
SplDoublyLinkedList (class) 15 メソッド
SplObjectStorage (class) 14 メソッド
SplPriorityQueue (class) 13 メソッド
ArrayIterator (class) 13 メソッド
SplFileInfo (class) 12 メソッド
=== 抽象クラス ===
FilterIterator
RecursiveFilterIterator
SplHeap
=== インターフェース ===
ArrayAccess
Countable
Iterator
IteratorAggregate
OuterIterator
RecursiveIterator
SeekableIterator
SplObserver
SplSubject
解説: ReflectionClass と組み合わせることで、SPL クラスの継承関係・メソッド数・抽象/具象の区別などを一括収集できます。ドキュメント自動生成やアーキテクチャ調査に活用できます。
サンプル5:動的なクラス存在チェックとフォールバック
実行環境で利用可能な SPL クラスを確認してから使うフォールバックパターンです。
<?php
declare(strict_types=1);
/**
* SPLクラスの可用性を確認してから使う安全なファクトリ
*/
class SplAwareFactory
{
private static ?array $available = null;
/**
* 利用可能なSPLクラス名のセットを返す(キャッシュ付き)
*
* @return array<string, true>
*/
private static function available(): array
{
if (self::$available === null) {
self::$available = array_fill_keys(array_keys(spl_classes()), true);
}
return self::$available;
}
public static function has(string $className): bool
{
return isset(self::available()[$className]);
}
/**
* 優先順位付きでスタック実装を選択
*/
public static function createStack(): object
{
if (self::has('SplStack')) {
return new SplStack();
}
// フォールバック:配列ベースの簡易スタック
return new class {
private array $data = [];
public function push(mixed $v): void { $this->data[] = $v; }
public function pop(): mixed { return array_pop($this->data); }
public function top(): mixed { return end($this->data); }
public function isEmpty(): bool { return empty($this->data); }
public function count(): int { return count($this->data); }
};
}
/**
* 優先順位付きでキュー実装を選択
*/
public static function createQueue(): object
{
if (self::has('SplQueue')) {
return new SplQueue();
}
return new class {
private array $data = [];
public function enqueue(mixed $v): void { $this->data[] = $v; }
public function dequeue(): mixed { return array_shift($this->data); }
public function isEmpty(): bool { return empty($this->data); }
public function count(): int { return count($this->data); }
};
}
}
// --- 使用例 ---
echo "SplStack 利用可能: " . (SplAwareFactory::has('SplStack') ? 'yes' : 'no') . "\n";
echo "SplQueue 利用可能: " . (SplAwareFactory::has('SplQueue') ? 'yes' : 'no') . "\n";
echo "SplHeap 利用可能: " . (SplAwareFactory::has('SplHeap') ? 'yes' : 'no') . "\n";
echo "NonExistent 利用可能: " . (SplAwareFactory::has('NonExistent') ? 'yes' : 'no') . "\n";
echo "\n";
$stack = SplAwareFactory::createStack();
$stack->push('first');
$stack->push('second');
$stack->push('third');
echo "スタック(" . get_class($stack) . "):\n";
while (!$stack->isEmpty()) {
echo " " . $stack->pop() . "\n"; // LIFO: third, second, first
}
実行結果:
SplStack 利用可能: yes
SplQueue 利用可能: yes
SplHeap 利用可能: yes
NonExistent 利用可能: no
スタック(SplStack):
third
second
first
解説: spl_classes() の結果をキャッシュしてハッシュマップ化(array_fill_keys)することで O(1) の存在チェックが実現できます。制限された環境(一部拡張が無効など)でのフォールバック実装に有効です。
サンプル6:SPL クラスカタログの自動生成
spl_classes() の情報から Markdown ドキュメントを自動生成するパターンです。
<?php
declare(strict_types=1);
class SplCatalogGenerator
{
private array $classes;
public function __construct()
{
$this->classes = array_keys(spl_classes());
sort($this->classes);
}
public function generateMarkdown(): string
{
$lines = [];
$version = PHP_VERSION;
$lines[] = "# PHP {$version} SPL クラス・インターフェース カタログ";
$lines[] = "";
$lines[] = "> 生成日時: " . date('Y-m-d H:i:s');
$lines[] = "> 総数: " . count($this->classes) . " クラス/インターフェース";
$lines[] = "";
foreach ($this->groupByCategory() as $category => $names) {
$lines[] = "## {$category}";
$lines[] = "";
$lines[] = "| クラス名 | 種別 | 抽象 | 説明 |";
$lines[] = "|---------|------|------|------|";
foreach ($names as $name) {
try {
$ref = new ReflectionClass($name);
$type = $ref->isInterface() ? 'Interface' : 'Class';
$abstract = ($ref->isAbstract() && !$ref->isInterface()) ? '✅' : '-';
$desc = $this->shortDescription($name);
$lines[] = "| `{$name}` | {$type} | {$abstract} | {$desc} |";
} catch (ReflectionException) {
$lines[] = "| `{$name}` | - | - | - |";
}
}
$lines[] = "";
}
return implode("\n", $lines);
}
/** @return array<string, list<string>> */
private function groupByCategory(): array
{
$groups = [
'データ構造' => [],
'反復子' => [],
'ファイル操作' => [],
'例外クラス' => [],
'インターフェース' => [],
'その他' => [],
];
foreach ($this->classes as $name) {
if (preg_match('/Stack|Queue|Heap|Priority|Linked|FixedArray/', $name)
&& str_starts_with($name, 'Spl')
) {
$groups['データ構造'][] = $name;
} elseif (str_ends_with($name, 'Iterator') || $name === 'EmptyIterator') {
$groups['反復子'][] = $name;
} elseif (str_starts_with($name, 'SplFile')) {
$groups['ファイル操作'][] = $name;
} elseif (str_ends_with($name, 'Exception')) {
$groups['例外クラス'][] = $name;
} elseif (interface_exists($name)) {
$groups['インターフェース'][] = $name;
} else {
$groups['その他'][] = $name;
}
}
return array_filter($groups, fn($v) => !empty($v));
}
private function shortDescription(string $name): string
{
return match (true) {
$name === 'SplStack' => 'LIFO スタック',
$name === 'SplQueue' => 'FIFO キュー',
$name === 'SplMinHeap' => '最小ヒープ',
$name === 'SplMaxHeap' => '最大ヒープ',
$name === 'SplPriorityQueue' => '優先度付きキュー',
$name === 'SplFixedArray' => '固定長配列',
$name === 'SplDoublyLinkedList' => '双方向リスト',
$name === 'SplObjectStorage' => 'オブジェクトストレージ',
$name === 'SplFileInfo' => 'ファイル情報',
$name === 'SplFileObject' => 'ファイルオブジェクト',
$name === 'SplTempFileObject' => '一時ファイルオブジェクト',
$name === 'ArrayIterator' => '配列の反復子',
$name === 'ArrayObject' => '配列をオブジェクトとして扱う',
$name === 'DirectoryIterator' => 'ディレクトリの反復子',
str_ends_with($name, 'Exception') => '例外クラス',
interface_exists($name) => 'インターフェース',
default => '-',
};
}
}
$generator = new SplCatalogGenerator();
$markdown = $generator->generateMarkdown();
// ファイルに保存
$outputPath = '/tmp/spl_catalog.md';
file_put_contents($outputPath, $markdown);
echo "カタログ生成完了: {$outputPath}\n";
echo "プレビュー(先頭30行):\n";
echo implode("\n", array_slice(explode("\n", $markdown), 0, 30)) . "\n";
実行結果(抜粋):
カタログ生成完了: /tmp/spl_catalog.md
プレビュー(先頭30行):
# PHP 8.3.x SPL クラス・インターフェース カタログ
> 生成日時: 2025-08-01 12:00:00
> 総数: 57 クラス/インターフェース
## データ構造
| クラス名 | 種別 | 抽象 | 説明 |
|---------|------|------|------|
| `SplDoublyLinkedList` | Class | - | 双方向リスト |
| `SplFixedArray` | Class | - | 固定長配列 |
| `SplMaxHeap` | Class | - | 最大ヒープ |
| `SplMinHeap` | Class | - | 最小ヒープ |
| `SplPriorityQueue` | Class | - | 優先度付きキュー |
| `SplQueue` | Class | - | FIFO キュー |
| `SplStack` | Class | - | LIFO スタック |
解説: spl_classes() の出力を起点に ReflectionClass で詳細情報を収集し、Markdown テーブルとして出力します。プロジェクトの内部ドキュメント生成やチーム向けリファレンスの自動更新に活用できます。
よくある落とし穴
① キーと値が同じことを忘れる
$classes = spl_classes();
// キーも値も同じ文字列なので、どちらを使っても同じ結果
foreach ($classes as $key => $value) {
var_dump($key === $value); // bool(true) 常に
}
// ✅ クラス名の一覧は array_keys() で取得するのが明示的
$names = array_keys(spl_classes());
② PHP バージョンによってクラス数が異なる
// PHP 5.x と PHP 8.x では利用可能な SPL クラスが異なる場合がある
// 実行環境に依存するクラスを使う前に必ず確認する
if (in_array('SplFixedArray', array_keys(spl_classes()), true)) {
$arr = new SplFixedArray(100);
}
③ spl_classes() はユーザー定義クラスを含まない
class MySplLike {}
// spl_classes() は SPL 組み込みのクラスのみを返す
$classes = spl_classes();
var_dump(isset($classes['MySplLike'])); // bool(false)
// ユーザー定義クラスの一覧は get_declared_classes() を使う
$all = get_declared_classes();
④ 戻り値は連想配列(isset で O(1) チェック可能)
// ❌ in_array は O(n) で遅い
if (in_array('SplStack', spl_classes(), true)) { /* ... */ }
// ✅ isset は O(1) で高速(キーでアクセス)
$classes = spl_classes();
if (isset($classes['SplStack'])) { /* ... */ }
まとめ
| ポイント | 内容 |
|---|---|
| 主な用途 | SPL クラス一覧の取得・環境チェック・ドキュメント生成 |
| 戻り値 | クラス名 => クラス名 の連想配列(キーと値が同じ) |
| 活用方法 | array_keys() で名前リスト・isset() で O(1) 存在チェック |
| 組み合わせ | ReflectionClass で詳細情報収集・interface_exists() で種別判定 |
| 注意点 | バージョン間差異あり・ユーザー定義クラスは含まない |
| 実用パターン | 環境差分検出・フォールバック実装・カタログ自動生成 |
spl_classes() は派手な機能を持つ関数ではありませんが、SPL という強力なライブラリを正しく把握・活用するための基盤となる情報源です。環境調査・ドキュメント生成・条件付きフォールバックなど、開発の幅広い場面で役立てましょう。
PHP 8.x / 執筆時点の最新安定版にて動作確認済み
