このコーナーについて
私は根っからの文系なのでプログラミングや情報技術についてはITパスポート程度の知識しかなく、現在は全くの独学でコードや言語等のスキルの勉強はチュートリアル等でコードを書いて成果物を作りながら学んでいけるが、それらの過程で出てくる用語や技術についてはイマイチ学びきれない。
なので、折に触れて書籍及びQlita記事等のネットサーフィンで学んだ座学的知識をアウトプットすることがこのコーナーの目的である。
今回
パーフェクトPHPで学ぶクラスの基本とコンストラクタ・デストラクタ
クラスの基本
<?php
class Employee {
private $test = 1;
public function work() { // 1
echo '書類を整理しています',PHP_EOL;
}
$yamada = new Employee(); // 2
$sasaki = new Employee();
$yamada->work(); // 3
$suzuki = $yamada; // 4
$suzuki = clone $yamada; // 5
?>
1
クラスを作る。設計図を書くイメージ。
2
クラスをインスタンス化する。これから設計図を使うぞって宣言だとイメージするといいかも。
なお、インスタンスはオブジェクトと呼称することもある。厳密な意味合いの違いは不明でインスタンスをオブジェクトといえば、オブジェクトをインスタンスと呼称する人もいる。
私はイメージとしてはインスタンスは設計図(クラス)を使うぞと宣言して、コピーを作り、オブジェクトはそのコピーした設計図をさらに使い回したものなのだなと大雑把に考えている。
なので、上記のようにインスタンス(オブジェクト)は同じクラスから複数作ることができる。
3
アロー演算子を使い、クラスの中にアクセスしている。
アクセスするのはキーと値がセットされているプロパティまたはクラスの中の関数であるメソッド。
4
$yamadaを$suzukiへオブジェクト参照するための橋渡しをするために使っている。
この場合、コピーされた変数(suzuki)に対する変更はコピー元の変数(yamada)にも反映される。
5
こちらは逆にオブジェクトへの参照ではなく、オブジェクトの複製。
よってオリジナルとコピーとで因果関係は生まれない。
詳しい使い方はマジックメソッドの__cloneの項目を参照。
アクセス修飾子
public // クラスの外側から参照・呼び出しができる。一番アクセス権限が緩い
private // 自分のクラスの内側からのみ参照・呼び出しができない。一番アクセス権限がきつい
protected // 自分のクラスとその派生クラスの内側からのみ参照・呼び出しができる。
<?php
$namae = "watanabe";
$obj1->hanasu();
class hito{
private $namae;
function hanasu(){
echo "私は $this->namae です。";
}
}
$test = new hito();
$test-> hanasu();
?>
// 私は です。
実行結果は以上の通り、$namae
の部分が空となってしまっている。
これはhitoクラスの中の$namae
のアクセス修飾子がprivateになっているので、クラスの外にある$namae = "watanabe";
を参照・呼び出しができていないためである。
publicであれば外側にある$namae = "watanabe"
を参照し、クラス内の変数$namae
に"watanabe"
が代入されるからエラーにならず、$test->hanasu();
が処理される。
プロパティとメソッド
<?php
class Employee {
public $name; // プロパティその1
public $state = "働いている"; // プロパティその2
public function work() { // メソッド
echo '書類を整理しています。',PHP_EOL;
}
}
$yamada = new Employee(); // 1
$yamada->name = "山田"; // 2
echo $yamada->state,$yamada->name,'さん:'; // 3
$yamada->work(); // 4
?>
// 働いている山田さん:書類を整理しています。
1
インスタンス化
2
プロパティにアクセスする。
$name
はキー、今回は値がないところにアクセスして値に"山田"
を代入するということをしている。
3
同様にプロパティにアクセス、$state
は上記の通りなので、結果「働いてる山田さん:」と出力される。
4
メソッドにアクセス、関数の処理が実行される。
余談ではあるが、あとからキーに値を代入する場合、空(null)にしたくない場合は変数は以下のようにしておくほうがいい。
<?php
$a = ""; // 文字列を後から値として代入したい時
$b = 0; // 数値を後から値として代入したい時
?>
$this
<?php
class Employee {
public $name;
private $state = '働いている';
public function getState() { // メソッド1
return $this->state;
}
public function setState($state) { // メソッド2
$this->state = $state;
}
public function work() {
echo '書類を整理しています',PHP_EOL;
}
}
$yamada = new Employee();
$yamada->name = "山田";
$yamada->setState('休憩している'); // メソッドにアクセスする。
echo $yamada->name,'さんは',$yamada->getState(),PHP_EOL;
?>
$this
はインスタンス自身を指す特別な変数である。踏み込んで言うと『$this
とはクラス定義内部でプログラムがアクセス可能なオブジェクト名(インスタンスメソッド)』であると言える。この場合はnew Employeeが$this
になる。例えば、private指定されている変数stateにアクセスしたいとする。当然クラスの外からはどうこうできないので、まずクラス内にメソッド1を作る。メソッド1はprivateなプロパティである$state
にアクセスするためのメソッド。ついで、それを変更するメソッドであるメソッド2を作る。
そして実際にsetStateメソッドにアクセスすると、Employeeクラスの中にあるsetStateメソッドにおける$thisは$yamada
を表すことになる。
よって、処理は以下のようになる
<?php
class Employee {
public $name;
private $state = '働いている';
public function getState() {
return $this->state;
}
public function setState($state) { // 3
$this->state = $state;
}
public function work() {
echo '書類を整理しています',PHP_EOL;
}
}
$yamada = new Employee();
$yamada->name = "山田"; // 1
$yamada->setState('休憩している'); // 2
echo $yamada->name,'さんは',$yamada->getState(),PHP_EOL; // 4
?>
1
$nameプロパティにアクセスして、山田という値を代入(セット)する。
2
setStateメソッドにアクセスする。
3
setStateメソッドが実行される。メソッドの処理コードが
$yamada->state = $state;
となるので、$stateの値が"休憩している"に変更される。
4
「山田さんは休憩している」と表示し、改行する。
$thisは最初は理解しにくい人もいると思うので、参考にさせて頂いたサイト載せておくのでぜひ一読してほしい。
ts0818のブログ:PHPで擬似変数$thisって何のためにあるのか?
static
<?php
// staticプロパティ
class Employee {
public $name;
public static $company = "出版社"
}
echo "従業員はみんな",Employee::$company,"に勤めています",PHP_EOL;
?>
プロパティやメソッドにstatic
をつけるとインスタンス化しなくてもそれらにアクセスすることができる。上はその例でクラスはあるが、インスタンス宣言はしていないのにも関わらずecho
で書き出しができている。
staticプロパティにアクセスするにはクラス名::の形で書く。
staticは静的ともいう。静的・動的についてはこちらを参考にしてほしい。
self
?php
class Employee {
public static $company = "出版社";
public function getCompany () {
return self::$company;
}
}
?>
$this
がインスタンスの代名詞のような使い方であったのに対し、クラスコンテキスト内部においてself
はそのクラス自身となる。つまり、クラスの代名詞のような使い方になる。
上の例ではself::$company
はEmployee::$company
と同義となる。
さらにこれがgetConmpany
メソッドの中に定義されているので、クラスの外からこのメソッドを使って$company
にアクセスすることもできる。
const
<?php
class Employee {
const PARTTIME = 1; // アルバイト
const REGULAR = 2; // 正社員
const CONTRACT = 3; // 契約社員
}
var_dump(Employee::REGULAR); // 結果はint(2)。
?>
constはクラス定数を定義する際に用いる。
クラス定数は定義したクラスの初期化時に用いられる設定のフラグやオプションに用いられるもので、要はデフォルトの値だと思えばいい。
アクセスするにはクラス名::定数名。
ここまでのまとめ
```php:メソッドで使う場合
<?php
class Employee {
(public)private static $company = "出版社"; // 1,4
public static function getCompany { // 2
return self::$company;
}
public static function setCompany($value) { // 3
self::$company = $value;
}
}
?>
メソッドも変数などと同じようにアクセス修飾子を用いることができる。
まず1はpublic static $company
となっていてpublic
がついているのと合わせてインタンス化せずとも外部から呼び出すことができるようになっている。
2も同じくstatic
なのでインスタンス化せずとも外部から呼び出せる。ここでは$compan
yを返す処理が定義されている。
3も以下略で処理は$company
に値(この場合は社名などだろう)を代入するという処理になっている。
つまり、この段階で$company
は外部から直接アクセスせずとも、実質アクセスできるような状態になっている。
すると不用意に外部から直接アクセスできるような状態にしておくのは望ましくないので、4でアクセス修飾子がpublic
からprivate
に変わるというのが上のコードの顛末ということになる。
なお、static
が記載されている場合、メソッドで$this
は用いることはできない。
コンストラクタとデストラクタ
<?php
class Employee {
const PARTTIME = 0x01;
const REGULAR = 0x02;
const CONTRACT = 0x04;
private $name;
private $type;
public function __construct($name,$type) {
$this->name = $name;
$this->type = $type;
}
}
$yamada = new Employee("山田",Employee::REGULAR);
var_dump($yamada);
?>
object(Employee)#1 (2) {
["name":"Employee":private]=>
string(6) "山田"
["type":"Employee":private]=>
int(2)
}
コンストラクタとデストラクタはクラスのインスタンスの作成・削除のタイミングで呼び出されるメソッド。
前者がインスタンスの作成をキーに実行されるメソッド、後者が削除をキーに実行されるメソッド。
実際はマジックメソッドと呼ばれる、PHPに備え付けられているメソッドのうちの1つなのだが詳しくは別項にて。
コンストラクタはインスタンスを宣言しオブジェクトを生成する際に必要なパラメータやそのクラスのオプションなどを引数と一緒に受け取り、プロパティにセットする。
例えば上記の例、まずクラス定数と変数を定義する。
次にpublic
でコンストラクタメソッドを定義する。このとき引数に先に定義した2つの変数を指定する。
ついでに中は$this
を用いてクラスの変数にアクセスできるようにしておく。
最後はインスタンス宣言、今回のポイントはここで引数を("山田",Employee::REGULAR)
と指定すること。
逆算していくと、$name
はコンストラクタメソッドにより$this->name = $name;
となっているので、わざわざ$yamda->name = "山田";
とわざわざ書かなくてもいいことになる。
また第2引数に$typeが指定されているので、そこにクラス定数であるEmployee::REGULAR
が代入される。
結果上記のような実行結果となる。
ちなみにここまでの処理をみればわかるが、今回のプロパティはコンストラクタメソッドにより外部から間接的にアクセスできるので、アクセス修飾子はprivateにするのが適切である。
デストラクタについてはPHP5.6.4以降より明示的に記述する必要はないので役割だけ覚えておこう。
実践してみる
<?php
// 閑話休題 オブジェクト指向基本のおさらい
class Robot {
private $name = "";
public function setName ($name) {
$this->name = (string)filter_var($name);
}
public function getName () {
return $this->name;
}
}
$a = new Robot();
$a->setName('アトム');
$b = new Robot( );
$b->setName('プルート');
echo $a->getName(); // アトム
echo $b->getName(); // プルート
?>
<!-- 外部には機能的にまとめられた最低限必要な情報しか公開しない。 -->
<?php
class Robot {
private $name = "";
public function __construct ($name) {
$this->setName($name);
}
public function setName($name) {
$this->name = (string)filter_var($name);
}
public function getName () {
return $this->name;
}
}
$a = new Robot('アトム');
$b = new Robot('プルート');
echo $a->getName(); // アトム
echo $b->getName(); // プルート
参考
パーフェクトPHP
PHPオブジェクト指向入門(前半)
ts0818のブログ:PHPで擬似変数$thisって何のためにあるのか?
わわわIT用語辞典