PHP入門:抽象クラス、インターフェース、外部ファイルの読み込み、名前空間
スプラトゥーン2の追加コンテンツ「オクト・エキスパンション」をやりたいがために早々と帰宅しましたが、そんな日でも勉強を欠かさない大人の鑑です。
今日も学ぶぜ。
#23
抽象クラスについて。抽象的な話になりそう…。
抽象クラスとは、他のクラスで継承してもらうことを前提としたクラスのこと。ここからインスタンスを作成することはできない。
abstract class BaseUser {
public $name;
abstract public function sayHi();
}
class User extends BaseUser {
}
このように、abstractというワードで抽象クラスであることを宣言する。
この例のsayHiメソッドは「このクラスを親とする子クラス(継承先のクラス)で必ずsayHiメソッドを実装してください」という意味になる。この時点ではまだ中身は決まっておらず、子クラスで決められるものになる。これを抽象メソッドという。
この例ではUserクラスがBaseUserの子クラスとなるが、UserでsayHiメソッドが定義されていない。この状態で実行しようとすると、ビルトインサーバー側で「Class User contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (BaseUser::sayHi)」というエラーを吐く。ごめんね。
抽象メソッドを子クラスで実装する際は親クラスのアクセス権やメソッド名、引数を必ず引き継がなければならないことに注意。
抽象クラスを使えば子クラスをシンプルにできたり、実装の漏れを防ぐことができる。
#24
インターフェース(interface)を使ってみようというお話。
インターフェースとは、「このクラスではこのメソッドを必ず実装してください」というルールを定義するための仕組みである。
interface sayHi {
public function sayHi();
}
interface sayHello{
public function sayHello();
}
class User Implements sayHi, sayHello{
}
インターフェースの特性上、メソッドのアクセス権は必ずpublicになるので注意。
また、メソッドの中身は実装するクラスで書くので、ここではメソッド名だけでよい。
このインターフェースを適用するクラスには、クラス名の後にImplementsと書き、その後ろにインターフェースの名前を書く(複数指定もカンマで区切れば可能)。
この状態で実行しようとすると、「Class User contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (sayHi::sayHi, sayHello::sayHello)」というエラーが出る。ごめんってば。
抽象クラスとインターフェースは似ているが、
- 抽象クラスではプロパティやメソッドの定義ができる。1つしか継承できない。
- インターフェースではできない(必ず実装するというメモ的な?)。複数実装できる。
という違いがある。
#25
外部ファイルを読み込んでみようというお話。
開発規模が大きくなればファイルを分割して保存することもあるので、今回はその方法を学ぶ。
class User {
public $name;
public function __construct($name){
$this->name=$name;
}
public function sayHi() {
echo "Hi,I am $this->name!";
}
}
$bob=new User("bob");
$bob->sayHi();
このコードのUserクラスを宣言している部分(1~9行目)を別のファイルに保存する。
今まで使っていたindex.phpと同じフォルダに「User.class.php」というファイルを作成し、上記のクラス部分をコピペする(User.class.php側で<?phpをつけるのを忘れない)。
今回はindex.phpからUser.class.phpを呼び出したい。方法としては、
- require
- require_once
- include
- include_once
- autoload
という5つの仕組みがある。なお、autoloadはクラスでのみ使える方法である。
requireもincludeも、それを書いた箇所に別ファイルを読み込む命令である。これらには以下の違いがある。
- require:エラー発生時にfatal errorを発生させ、その場で処理が終了する
- include:エラー発生時にwarningを発生させ、処理を続行する
requireとrequire_once、includeとinclude_onceの違いについて、_onceがついている方はPHPが自動的にそのファイルが読み込まれているかをチェックし、既に読み込まれている場合はその箇所での読み込みをスキップするというもの。
今回はrequireを使い、index.phpをこのように書き換える。
require "User.class.php";
$bob=new User("bob");
$bob->sayHi();
こうすることでUser.class.phpの内容が読み込まれるので、処理が正常に通る(画面に「Hi,I am bob!」と表示される)。
autoloadについてだが、クラスが未定義だった場合に自動的に実行される仕組みである。今回の例ではindex.php側で以下のように書くが、今のところおまじないみたいに思っておけばいいとのこと。
spl_autoload_register(function($class) {
require $class . ".class.php";
});
$bob=new User("bob");
$bob->sayHi();
これでうまく処理が通る。不思議。
#26
名前空間を使ってみようという話。
別ファイルを複数読み込んだ時、クラス名がかぶってしまうと問題になる。そのためにも、自分が作った関数、クラス、インターフェースには名前空間をつけて重複しないようにする。
今回はUser.Class.phpを以下のようにする。
namespace Dotinstall\lib;
class User {
public $name;
public function __construct($name){
$this->name=$name;
}
public function sayHi() {
echo "Hi,I am $this->name!";
}
}
namespace (名前空間の名称)とすれば宣言できる。名前空間はフォルダのように階層分けできるので、その際にはバックスラッシュをつけて深い階層の名前を書いて…の繰り返しになる。namespaceは必ずファイルの先頭に書くことがルール。
この名前空間を生かすには、index.phpを以下のように書き換える。
require "User.class.php";
$bob=new Dotinstall\lib\User("bob");
$bob->sayHi();
どの名前空間に属するクラスなのかを明示する形となる。なお、User.class.phpで名前空間を宣言したがindex.php側でそれを書いていない場合はエラーになるので注意。名前空間を使うなら両方とも書くこと。
階層のように管理していくと名前空間の名前がやたら長くなってしまう。それを防ぐために別名をつけることが可能。index.php側を以下のようにする。
require "User.class.php";
use Dotinstall\lib as lib;
$bob=new lib\User("bob");
$bob->sayHi();
use (名前空間の名前) as (別名)という形で宣言し、以降は別名が使える。別名の宣言の方法には別の方法もあり、
use Dotinstall\lib;
このようにuseの部分を書き換えることで、階層の最後となる名前をそのまま名前空間の略称として用いる。
他の人が開発したライブラリを使うときなどによく見るらしいので覚えておこう。
今夜の勉強はここまでで、明日にはドットインストールのPHP入門編が終了する予定です。そのあとはPHPの本を買っているので、それに載っている作品例を作りながら今までの復習や発展的な学習に進みます。場合によってはJavascriptにも手を伸ばすかもしれない。何かオリジナルのWebサービスも作ってみたい。
さて、オクトやるぞー。