1. 本記事のポイント
- PHPのプロシージャルコードをOOP(オブジェクト指向)へ変換する基本手順を解説
- リファクタリング時の典型パターンと実務判断のポイントを紹介
- コードの保守性や拡張性を意識した設計への足がかりに
2. PHPプロシージャルからOOPへのリファクタリングとは?
PHPはもともとスクリプト言語として、HTML埋め込み型のプロシージャルコード(手続き型)を中心に発展してきました。しかし、近年ではフレームワークを含む多くの現場でオブジェクト指向プログラミング(OOP)が標準化されています。
プロシージャルコードでは、処理の流れを上から順に書き並べ、関数や変数をグローバルに扱うことが多く、スクリプトが大きくなるにつれ保守性に課題が出やすくなります。一方、OOPではデータと処理をクラスとして整理し、再利用性や拡張性、テストのしやすさが向上します。
本記事では、典型的なプロシージャルコードをOOPに書き換える過程を通じて、リファクタリングの実務的な考え方や注意点を解説します。
3. 詳細解説
以下のような簡単なプロシージャルコードからスタートします。ここでは商品価格に税率を加味して税込価格を出力しています。
// プロシージャルな処理
function calcTax($price) {
return $price * 1.1; // 税率10%
}
$price = 1000;
echo '税込価格: ' . calcTax($price);
// 出力: 税込価格: 1100
この処理をOOPにリファクタリングしてみます。まずは処理をクラス化し、責務を分離します。
// 単一責任に基づく設計
class TaxCalculator {
private float $rate;
public function __construct(float $rate = 0.1) {
$this->rate = $rate;
}
public function withTax(float $price): float {
return $price * (1 + $this->rate);
}
}
$calculator = new TaxCalculator();
echo '税込価格: ' . $calculator->withTax(1000);
// 出力: 税込価格: 1100
次に、外部入力を含む処理に対応するためのクラス構成を検討します。以下は「商品」と「価格計算」の関心を分離した例です。
class Product {
public function __construct(
private string $name,
private float $price
) {}
public function getPrice(): float {
return $this->price;
}
}
class TaxCalculator {
public function __construct(private float $rate = 0.1) {}
public function calculate(Product $product): float {
return $product->getPrice() * (1 + $this->rate);
}
}
$product = new Product('Tシャツ', 2500);
$calculator = new TaxCalculator();
echo '税込価格: ' . $calculator->calculate($product);
// 出力: 税込価格: 2750
このように、OOPでは状態と振る舞いを適切にクラスへ分けることで、変更や拡張への耐性が向上します。また、DI(依存性注入)やテストフレンドリーな構成にもつながります。
4. よくあるミス・誤解・落とし穴
OOP化において「なんでもクラス化すればよい」と誤解しがちですが、構造を分ける意図が不明瞭な場合、かえって可読性が下がる危険もあります。
また、getter/setterだけを持つデータコンテナの乱用や、関心の混ざったGod Object的設計もよく見られます。設計の目的は「整理」や「再利用性の向上」であることを忘れず、処理やデータのまとまりを意識しましょう。
さらに、グローバル変数をそのままクラスに持ち込んでしまい、状態管理が煩雑になるケースも多くあります。OOPではスコープやライフサイクルを適切に管理する必要があります。
5. まとめ
PHPのプロシージャルコードをOOPへリファクタリングすることで、保守性や拡張性が向上します。単純な関数呼び出しからスタートし、責務に応じてクラスを分離・構成することが基本です。
ただし、過度な抽象化やクラス化は逆効果になるため、「どのような目的で分けるか」を明確に意識しながら進めることが重要です。