毎日の開発では、 SPRINTF関数を使用して、固定小数点で数値を出力する、出力コンテンツを整列するなどの文字列をフォーマットすることがよくあります。ただし、このフォーマットロジックを「自動化」できる場合、つまりオブジェクトのメタ情報を自動的にフォーマットすることができれば(クラスのプロパティやフォーマットの説明など)、柔軟性を大幅に向上させます。
PHPの反射APIは、実行時にクラス、プロパティ、および方法を分析するメカニズムを提供します。 SPRINTFの強力なフォーマット機能と組み合わせることで、「自動フォーマットツール」を実装できます。これは、クラスプロパティの注釈または命名規則に基づいてオブジェクトをフォーマットおよび出力できます。
次の効果を達成したい:
$user = new User('Alice', 5, 1234.5678);
echo AutoFormatter::format($user);
出力の結果は次のとおりです。
Name: Alice | Level: 005 | Balance: $1234.57
形式は、フォーマット関数でハードコーディングされるのではなく、クラスの定義によって決定されます。
PHP 8属性を使用して、クラスの属性にフォーマット命令を追加します。
#[Attribute]
class Format {
public function __construct(public string $format) {}
}
class User {
#[Format('%-10s')] // 左アライメント,占める10少し
public string $name;
#[Format('%03d')] // 整数,ゼロを補充します3少し
public int $level;
#[Format('$%.2f')] // 保留两少し小数,ドル記号を追加します
public float $balance;
public function __construct($name, $level, $balance) {
$this->name = $name;
$this->level = $level;
$this->balance = $balance;
}
}
リフレクションを使用して、対応する形式のプロパティを読み取り、フォーマットされた文字列を生成します。
class AutoFormatter {
public static function format(object $obj): string {
$refClass = new ReflectionClass($obj);
$values = [];
$formats = [];
foreach ($refClass->getProperties() as $prop) {
$prop->setAccessible(true);
$value = $prop->getValue($obj);
$attrs = $prop->getAttributes(Format::class);
if (!empty($attrs)) {
$formatAttr = $attrs[0]->newInstance();
$formats[] = $formatAttr->format;
$values[] = $value;
}
}
$formatString = implode(' | ', $formats);
return sprintf($formatString, ...$values);
}
}
$user = new User('Alice', 5, 1234.5678);
echo AutoFormatter::format($user);
// 出力:Name: Alice | Level: 005 | Balance: $1234.57
Webインターフェイスに適用する場合は、フォーマットされた結果を返すだけです。
header('Content-Type: text/plain');
echo AutoFormatter::format(new User('Bob', 42, 98765.4321));
また、これらの形式をロギング、テンプレートレンダリング、またはAPI応答に使用することもできます。例えば:
file_put_contents('https://gitbox.net/logs/user.log', AutoFormatter::format($user), FILE_APPEND);
PHPのSprintfと反射を組み合わせることにより、アプリケーションコードからフォーマットロジックを抽出して、高度に分離され構成可能な自動フォーマット関数を実現できます。これにより、コードがよりエレガントになるだけでなく、将来の形式の変更にも非常に便利になります。
この方法は、統一された形式の出力を必要とするロギング、エクスポート、レポートなどのシナリオに特に適しています。