PHPでFactory Methodを使う方法!生成処理をクラスから分離する設計
新人
「Factory Methodを学ぶとき、サンプルを写すだけで終わらないようにしたいです。」
先輩
「それなら、小さなWebアプリの責務分割という具体例に置き換えて考えるといいですよ。使う値、処理、表示結果が見えると理解しやすくなります。」
新人
「コードのどこを変えれば応用できるかも知りたいです。」
先輩
「では、Factory Methodを中心に、入力チェック、表示、関数化、ログまで順番に見ていきましょう。」
1. Factory Methodを使う場面と使わない場面
Factory Methodは、用語だけを見ると難しく感じますが、実際には「どの値を受け取り、どの形へ整えて、どこへ表示または保存するか」を決める作業です。この記事では 小さなWebアプリの責務分割 を題材に、手を動かしながら流れを確認します。
<?php
class Lesson
{
public function __construct(
private string $title,
private int $price
) {}
public function label(): string
{
return $this->title . ":" . number_format($this->price) . "円";
}
}
$lesson = new Lesson("PHP設計入門", 3000);
echo htmlspecialchars($lesson->label(), ENT_QUOTES, "UTF-8");
?>
2. Factory Methodで責務を分ける最小コード
まずは最小コードで動きを見ます。大きな機能にする前に、Factory Method の役割、入力値、出力結果を小さく確認しておくと、あとでエラーが出たときにも原因を追いやすくなります。
<?php
$value = trim($_POST["value"] ?? "");
$errors = [];
if ($value === "") {
$errors[] = "値を入力してください。";
}
if (mb_strlen($value, "UTF-8") > 100) {
$errors[] = "100文字以内で入力してください。";
}
if ($errors) {
foreach ($errors as $error) {
echo htmlspecialchars($error, ENT_QUOTES, "UTF-8") . "<br>";
}
}
?>
3. if文が増えすぎる処理を差し替え可能にする
実務では、入力値が空だったり、想定外の文字列が入ったりします。ここを先にチェックしておくと、画面崩れ、DBエラー、意図しない処理をかなり減らせます。
<?php
function escapeHtml(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES, "UTF-8");
}
$rows = [
["title" => "PHPサンプル", "status" => "公開"],
["title" => "入力チェック", "status" => "確認中"],
];
?>
<table>
<?php foreach ($rows as $row): ?>
<tr>
<td><?php echo escapeHtml($row["title"]); ?></td>
<td><?php echo escapeHtml($row["status"]); ?></td>
</tr>
<?php endforeach; ?>
</table>
4. Controllerから業務ロジックを追い出す
PHPで画面へ出す値は、基本的に表示直前でエスケープします。自分で用意した配列でも、将来フォームやDBから来る値へ変わる可能性があるため、安全な表示を習慣にします。
<?php
function normalizeText(?string $value): string
{
$value = trim($value ?? "");
return mb_convert_kana($value, "s", "UTF-8");
}
$keyword = normalizeText($_GET["keyword"] ?? "");
echo htmlspecialchars($keyword, ENT_QUOTES, "UTF-8");
?>
5. テスト用の実装に切り替えやすくする
同じ処理が2回以上出てきたら、関数化を考えます。短い関数へ切り出すと、名前から目的が分かり、テストや修正もしやすくなります。
<?php
try {
$result = ["ok" => true, "message" => "処理が完了しました。"];
if (!$result["ok"]) {
throw new RuntimeException($result["message"]);
}
} catch (Throwable $e) {
error_log($e->getMessage());
echo "エラーが発生しました。";
}
?>
6. 小規模アプリで設計パターンを使いすぎない判断
エラー対策では、利用者へ見せるメッセージと、開発者が調査するログを分けます。画面にはやさしい文言、ログには日時やURLなど調査に必要な情報を残すと運用しやすくなります。
<?php
$log = [
"time" => date("Y-m-d H:i:s"),
"uri" => $_SERVER["REQUEST_URI"] ?? "",
"ip" => $_SERVER["REMOTE_ADDR"] ?? "",
];
error_log(json_encode($log, JSON_UNESCAPED_UNICODE));
?>
7. 小さなWebアプリの責務分割で使える実務コード
小さなWebアプリの責務分割として使うなら、コードを1つの流れとして読めることが大切です。入力、処理、表示、エラー処理が離れすぎると、初心者は原因を見失いやすくなります。
まずは小さく動く形を作り、あとからDB保存、メール送信、ログ出力、テストを足していくと、無理なく実務的なコードへ育てられます。
8. LaravelやMVCへ進む前に確認したいこと
Factory Methodを復習するときは、サンプルの変数名だけを変えるのではなく、入力値の種類、空データ、エラー時の表示まで変えて試してみましょう。そこまで確認すると、ただ動くコードから、壊れにくいPHPコードへ近づきます。
次の練習では、小さなWebアプリの責務分割に検索条件、保存処理、権限チェックのどれか1つを追加してみてください。記事ごとのテーマを小さな機能へ落とし込むほど、学習記事としても実務メモとしても価値が出ます。