-
PDO とは PHP Data Objects の略称で、アクセス先のデータベースの種類を意識することなく、アクセスできるようにしたクラスです。
今まではMySQLへ接続する場合は「mysql_connect」関数を使用し、PostgreSQLの場合は「pg_connect」関数で行っていました。 また、SQL実行などもそれぞれの関数を使用しなければなりませんので、データベースごとに異なるクラスを使用する必要があります。
しかし、PDO であればデータベースの違いを吸収してくれますので、同じソースで各データベースにアクセスできます。 (厳密な意味においては、データベース毎の特殊な処理とか、SQLの違いはありますが。)
この記事では、データベースへの接続とテーブルレコード取得を説明します。
テーブルに対しての登録(INSERT)、更新(UPDATE)、削除(DELETE)については、別の記事で説明します。- データベースへの接続
- テーブルレコード取得(SELECT : query)の例
- テーブルレコード取得(SELECT : query)の複数取得の例
- テーブルレコード取得(SELECT : prepare, excute)の例
■データベースへの接続
そこで、先ずは mysql データベースへの接続に付いて説明します。
PDOクラスでは、インスタンス生成を行うと同時に接続を行います。
PDOクラスのコンストラクタ(クラス生成時の関数)は以下の様な宣言になっています。public PDO::__construct ( string $dsn [, string $username [, string $passwd [, array $options ]]] ) $dsn データソース名(Data Source Name)で、データベースに接続するために 必要な情報が含まれます。 $username ユーザ名 $passwd パスワード $options ドライバ固有の接続オプションを指定する配列 返り値: 接続成功時に PDO オブジェクトを返します。 エラー: データベースへの接続に失敗した場合 PDOException を投げます。
尚、データソース名(DSN)の指定は以下の様になります。// DSN指定文字列 mysql:host=hostname;port=portno;dbname=databasename hostname データベースサーバが存在するホスト名 portno データベースサーバーが待機しているポートNO databasename データベース名
実際にデータベースへの接続を行うソースを見て下さい。 ホストは xampp と共にインストールした MySQL への接続を行っています。
尚、 Windowsコマンドプロンプトで実行するため echo 出力が文字化けしない様に、先頭でコンソール出力への文字コード変換用に 関数を定義しています。
最後の行で、接続を閉じるために PDO オブジェクト変数に null を設定しています。 この処理によって明示的にデータベースへの接続を閉じることが出来ます。 この処理が無くても、スクリプトの終了時にデータベースへの接続を閉じられますが、書いた方が無難かと思います。<?php // Windowsコマンドプロンプトで実行するために、コンソール出力を UTF-8 ⇒ Shift-JIS 変換 ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); echo "データベース接続OK\n"; } catch (PDOException $e) { // エラー発生 echo 'データベース接続ERROR:'.$e->getMessage()."\n"; exit(); } // データベースへの処理... // 接続を閉じる $pdo = null; ?>これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo1.php データベース接続OK
MySQL は起動されていて pdo と名付けられたデータベースは存在するので、接続OKと表示されます。
そこで エラーを発生させるためにデータベース名を間違ったものにしてみます。 5行目の「pdo」 を 「pdo1」 にして上記のソースを実行します。C:\xampp\htdocs\_test>php pdo1.php データベース接続ERROR:SQLSTATE[HY000] [1049] Unknown database 'pdo1'
さらにパスワードを間違ったものにしてみます。 7行目の 'password' の中身を 'passwordx' にして上記のソースを実行します。
C:\xampp\htdocs\_test>php pdo1.php データベース接続ERROR:SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)
■テーブルレコード取得(SELECT : query)の例
まず最初に pdo データベースにテスト用のテーブルを作成します。 テーブルは商品マスタ的なものとし 「ID」「名称」「単価」のカラムを持つ簡単なものにします。
データベースを生成し、商品マスタ(tm_shohin)テーブルを生成後、数件のデータを登録しています。 これらの処理をコマンドプロンプトから mysql を起動し実行した結果が以下の様になります。MariaDB [(none)]> CREATE DATABASE IF NOT EXISTS `pdo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; Query OK, 1 row affected (0.03 sec) MariaDB [(none)]> use pdo Database changed MariaDB [pdo]> CREATE TABLE `tm_shohin` ( -> `id` bigint(20) NOT NULL, -> `name` varchar(100) DEFAULT NULL, -> `price` bigint(20) DEFAULT NULL -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.50 sec) MariaDB [pdo]> ALTER TABLE `tm_shohin` -> ADD PRIMARY KEY (`id`); Query OK, 0 rows affected (1.34 sec) Records: 0 Duplicates: 0 Warnings: 0 MariaDB [pdo]> desc tm_shohin; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | id | bigint(20) | NO | PRI | NULL | | | name | varchar(100) | YES | | NULL | | | price | bigint(20) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) MariaDB [pdo]> set names cp932; Query OK, 0 rows affected (0.00 sec) MariaDB [pdo]> INSERT INTO `tm_shohin` (`id`, `name`, `price`) VALUES -> (1, 'パソコン001', 100000), -> (2, 'パソコン002', 202000), -> (3, 'パソコン003', 303000), -> (4, 'プリンタ001', 50000), -> (5, 'プリンタ002', 150000); Query OK, 5 rows affected (0.08 sec) Records: 5 Duplicates: 0 Warnings: 0 MariaDB [pdo]> select * from tm_shohin; +----+-------------+--------+ | id | name | price | +----+-------------+--------+ | 1 | パソコン001 | 100000 | | 2 | パソコン002 | 202000 | | 3 | パソコン003 | 303000 | | 4 | プリンタ001 | 50000 | | 5 | プリンタ002 | 150000 | +----+-------------+--------+ 5 rows in set (0.00 sec)準備は整いましたので、PDOオブジェクトの queryメソッドを使ってデータを取得してみます。 (queryメソッドの説明は本家のマニュアルから以下となります)
// queryメソッド定義 public PDO::query ( string $statement ) : PDOStatement $statement 準備、発行する SQL ステートメント。 返り値: PDOStatement オブジェクトを返します。 失敗した場合は FALSE を返します。 PDO::query() は、一回の関数コールの中で SQL ステートメントを実行し、このステートメントにより返された 結果セット (ある場合) を PDOStatement オブジェクトとして返します。 複数回発行する必要があるステートメントの場合、 PDO::prepare() で PDOStatement ステートメントを準備し、 PDOStatement::execute() でそのステートメントを 複数回発行する方がより良いパフォーマンスを得られると実感するでしょう。 PDO::query() を次にコールする前に 結果セット内の全てのデータを取得しない場合、そのコールは失敗します。 PDOStatement::closeCursor() をコールし、 次に PDO::query() をコールする前に PDOStatement オブジェクトに関連付けられたリソースを解放してください。
この query メソッドにSQL文を渡し、返される PDOStatement オブジェクトの fetch メソッドでデータ取得を行います。 (queryメソッドの説明は本家のマニュアルから以下となります)// fetchメソッド定義 public PDOStatement::fetch ([ int $fetch_style [, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int $cursor_offset = 0 ]]] ) : mixed $fetch_style レコードを呼び出し元に返す方法を制御します。 PDO::FETCH_* 定数のどれかで、デフォルトは PDO::FETCH_BOTH です。 $cursor_orientation スクロール可能なカーソルを表す PDOStatement オブジェクトの場合、 この値により呼び出し側に返される行を定義します。 $cursor_offset スクロール可能なカーソルを表すPDOStatementオブジェクトの場合で、 cursor_orientationパラメータが PDO::FETCH_ORI_ABSに設定された場合、 この値により 取得される結果セットの行の絶対位置が指定されます。 返り値: この関数が成功した場合の返り値は、取得形式によって異なります。 失敗した場合は常に FALSE を返します。queryメソッドは第1引数しか使ったことが無く、通常でしたら引数無しでも十分です。 それでは、商品マスタから「id = 1」の行を取得し表示するソースを以下に示します。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // データ取得SQL(結果が1行しか返さない) $sql = "select * from `tm_shohin` where id = 1"; // SELECTクエリの実行 $pdostmt = $pdo->query($sql); // PDOStatementクラスの fetch メソッドで1行のデータ取得 $result = $pdostmt->fetch(); // データ表示 echo "id :".$result["id"]."\n"; echo "name :".$result["name"]."\n"; echo "price:".$result["price"]."\n"; // 接続を閉じる $pdo = null; ?>これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo2.php id :1 name :パソコン001 price:100000
変数 $result を print_r で見てみると以下の様になります。 カラム名とカラム位置のキーでデータの配列が設定されていることが分かります。
Array ( [id] => 1 [0] => 1 [name] => パソコン001 [1] => パソコン001 [price] => 100000 [2] => 100000 )■テーブルレコード取得(SELECT : query)の複数取得の例
上記のスクリプトでは1件のデータのみの取得を行いましたが、1回目の fetch 処理の後、再度 fetch を行うとどうなるでしょうか?
では以下のスクリプトを実行してみます。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // データ取得SQL(結果が1行しか返さない) $sql = "select * from `tm_shohin` where id = 1"; // SELECTクエリの実行 $pdostmt = $pdo->query($sql); // PDOStatementクラスの fetch メソッドで1行のデータ取得 $result = $pdostmt->fetch(); // データ内容表示 var_dump($result); // 再度の fetch メソッド実行 $result = $pdostmt->fetch(); // データ内容表示 var_dump($result); // 接続を閉じる $pdo = null; ?>これを実行すると以下の様に表示されます。
array(6) { ["id"]=> string(1) "1" [0]=> string(1) "1" ["name"]=> string(15) "パソコン001" [1]=> string(15) "パソコン001" ["price"]=> string(6) "100000" [2]=> string(6) "100000" } bool(false)1回目の fetch 処理後は変数 $result には配列データが返っていますが、 2回目の fetch 処理後は false が返っています。 これは、2回目の fetch でエラーが発生したことを示しています。
指定されたSQL文は1件のデータしか返さないので、2回目の取得ではエラーが発生するのは当然です。
もし複数のデータを返すSQL文で、連続して fetch 処理を行う場合に $result の内容が false であれば、 データの最後まで来て終わったことを示します。 では、複数データを返す例を以下のスクリプトで示します。<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // データ取得SQL(全てのデータを「id」昇順に取得) $sql = "select * from `tm_shohin` order by id"; // SELECTクエリの実行 $pdostmt = $pdo->query($sql); // PDOStatementクラスの fetch メソッドで1行のデータ取得 while ($result = $pdostmt->fetch()) { // データの取得と終りの判定を同時に行う!! // データが取得できた場合(データ表示) echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "end...\n"; // 接続を閉じる $pdo = null; ?>これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo4.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 id:5 name :プリンタ002 price:150000 end...
■テーブルレコード取得(SELECT : prepare, excute)の例
データ取得の方法は query メソッドを使用する他に、 prepare, excute メソッドを使用する方法があります。
// prepareメソッド定義 public PDO::prepare ( string $statement [, array $driver_options = array() ] ) : PDOStatement $statement 有効な SQL 文のテンプレート $driver_options この配列はこのメソッドによって返される PDOStatement オブジェクトに対して 1 もしくはそれ以上の key=>value の組を含みます。 返り値: データベースサーバーが正常に文を準備する場合、PDO::prepare() は PDOStatement オブジェクトを返します。 もしデータベースサーバーが文を準備できなかった場合、 PDO::prepare() は FALSE を返すか PDOException を発行します (エラー処理 の方法に依存します)。このメソッドで指定するSQL文のテンプレートは、後から指定される値で置き換えされるパラメータ識別子を含むものになります。 以下にその例を記します。
// 名前付きパラメータを用いて SQL ステートメントのテンプレート select * from `tm_shohin` where id >= :id1 and id <= :id2; // 疑問符パラメータを用いて SQL ステートメントのテンプレート select * from `tm_shohin` where id >= ? and id <= ?;
名前付きパラメータのSQLは「:id1」「:id2」がパラメータで、疑問符パラメータのSQLは2個の「?」マークがパラメータです。
尚、このSQL文を prepare メソッドで実行し、返された PDOStatement オブジェクトの excute メソッドでパラメータを指定し、 SQLの実行を行います。// executeメソッド定義 public PDOStatement::execute ([ array $input_parameters = NULL ] ) : bool $input_parameters 実行される SQL 文の中のバインドパラメータと同数の要素からなる、値の配列。 すべての値は PDO::PARAM_STR として扱われます。 ひとつのパラメータに対して複数の値をバインドすることはできません。 例えば、IN() 句の中のひとつのパラメータに対して 2 つの値をバインドすることはできません。 返り値: 成功した場合に TRUE を、失敗した場合に FALSE を返します。それでは、名前付きパラメータと疑問符パラメータを用いた場合のスクリプトを以下に記します。
<?php ob_start(function($buf){ return mb_convert_encoding($buf, 'SJIS', 'UTF-8'); }); // MySQLデータベースに接続 $dsn = "mysql:host=localhost;dbname=pdo;"; $user = 'root'; $password = 'password'; try { // PDOクラス生成(データベース接続) $pdo = new PDO($dsn, $user, $password); } catch (PDOException $e) { // エラー発生 die('データベース接続ERROR:'.$e->getMessage()."\n"); } // データ取得SQL(名前付きパラメータ) $sql = "select * from `tm_shohin` where id >= :id1 and id <= :id2 order by id"; // SELECTクエリのprepare $pdostmt = $pdo->prepare($sql); // SELECTクエリのパラメータに実際の値設定 $pdostmt->execute(array(":id1" => "1", ":id2" => "3")); // PDOStatementクラスの fetch メソッドで1行のデータ取得 while ($result = $pdostmt->fetch()) { // データが取得できた場合(データ表示) echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "end...1\n"; // データ取得SQL(疑問符パラメータ) $sql = "select * from `tm_shohin` where id >= ? and id <= ? order by id"; // SELECTクエリのprepare $pdostmt = $pdo->prepare($sql); // SELECTクエリのパラメータに実際の値設定 $pdostmt->execute(array(0 => "1", 1 => "4")); // array("1", "4") でもOK // PDOStatementクラスの fetch メソッドで1行のデータ取得 while ($result = $pdostmt->fetch()) { // データが取得できた場合(データ表示) echo "id:".$result["id"]." name :".$result["name"]." price:".$result["price"]."\n"; } echo "end...2\n"; // 接続を閉じる $pdo = null; ?>これを実行すると以下の様に表示されます。
C:\xampp\htdocs\_test>php pdo5.php id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 end...1 id:1 name :パソコン001 price:100000 id:2 name :パソコン002 price:202000 id:3 name :パソコン003 price:303000 id:4 name :プリンタ001 price:50000 end...2
よほどのことが無ければ「疑問符パラメータ」は使用しないと思います。「名前付きパラメータ」の方が分かりやすいと思います。
PR -
PHP においても Windows の様にINIファイルを読込んで設定値として利用できる関数があります。
それが parse_ini_file で関数の引数にINIファイルのファイル名を指定すれば、INIファイルの中身を全て配列として返してきます。 Windows のINIファイル用の API と較べれば非常に簡単です。
■parse_ini_file の使用例
関数定義は以下の通りです。
// 関数定義 array parse_ini_file ( string $filename [, bool $process_sections = false [, int $scanner_mode = INI_SCANNER_NORMAL ]] ) [引数] $filename ini ファイル指定 $process_sections TRUE を設定するとセクション名と設定が含まれた多次元の配列を得ることができます $scanner_mode INI_SCANNER_NORMAL (デフォルト) または INI_SCANNER_RAW を指定すると、 オプションの値はパースされません。 PHP 5.6.1 以降では INI_SCANNER_TYPED も指定でき、 boolean や null そして integer の型を、可能な限り維持します [返り値] 成功した場合に設定を連想配列形式で返します。 失敗した場合に FALSE を返します。それでは以下のINIファイルを読込んでみます。
; これはテストINIファイルです。[test.ini] [section1] data1 = 1 data2 = 1000 data3 = abcde [section2] string1 = "aaa123" string2 = "bbbbb11" [section3] array1[] = "100" array1[] = "200" array1[] = "300" array2["test1"] = "test1aaa" array2["test2"] = "test2bbbbb"
以下にセクションを意識する指定と、そうでない指定で行ってみます。<?php // $process_sections 未指定 $arr = parse_ini_file("test.ini"); print_r($arr); // $process_sections 指定 $arr = parse_ini_file("test.ini", true); print_r($arr); ?>実行結果は以下の様に表示されます。
Array ( [data1] => 1 [data2] => 1000 [data3] => abcde [string1] => aaa123 [string2] => bbbbb11 [array1] => Array ( [0] => 100 [1] => 200 [2] => 300 ) [array2] => Array ( [test1] => test1aaa [test2] => test2bbbbb ) ) Array ( [section1] => Array ( [data1] => 1 [data2] => 1000 [data3] => abcde ) [section2] => Array ( [string1] => aaa123 [string2] => bbbbb11 ) [section3] => Array ( [array1] => Array ( [0] => 100 [1] => 200 [2] => 300 ) [array2] => Array ( [test1] => test1aaa [test2] => test2bbbbb ) ) )セクションを指定すると、セクション毎に配列となり、セクション以下は更にその中の配列になっています。
■parse_ini_file の使用例その2
私のPHPは PHP Version 5.6.28 ですので、第3引数を INI_SCANNER_TYPED の指定を行い実行してみます。
内部的に文字列なのか、数値なのかが分かりにくいので出力は var_dump を使います。<?php // $process_sections 指定 $arr = parse_ini_file("test.ini", true, INI_SCANNER_TYPED); var_dump($arr); ?>実行結果は以下の様に表示されます。数値として判断できるデータは数値になっています。
array(3) { ["section1"]=> array(3) { ["data1"]=> int(1) ["data2"]=> int(1000) ["data3"]=> string(5) "abcde" } ["section2"]=> array(2) { ["string1"]=> string(6) "aaa123" ["string2"]=> string(7) "bbbbb11" } ["section3"]=> array(2) { ["array1"]=> array(3) { [0]=> string(3) "100" [1]=> int(200) [2]=> string(3) "300" } ["array2"]=> array(2) { ["test1"]=> string(8) "test1aaa" ["test2"]=> string(10) "test2bbbbb" } } }
-
以下の記事で、クラス(class)のオーバーライドの使い方について説明してきました。
⇒PHP クラス(class)の使い方について
⇒PHP クラス(class)のオーバーライドの使い方について・その2
そこで、今回は簡単なクラスでの説明ではなく、少し有用性があるクラスを作成し、それを元にオーバーライドの使い方について説明します。
以下のクラスは PHPExcel ライブラリを利用して指定されたエクセルファイルをオープンし、全ての行を順次読込むためのクラスです。 メソッドとしては以下の4個を持ちます。- コンストラクタ(__construct):ファイルを指定してインスタンス生成
- ファイルオープン(open):ファイルをオープンして各種属性を取得
- カラムMAX取得(getColMax):カラムの最大値を返す
- 1行データ取得(getLine):データが存在した場合は配列データを返す(最後を超えた場合はfalse)
<?php // Excelライブラリ読込 require_once './PHPExcel-1.8/Classes/PHPExcel.php'; // Excelファイル読込クラス[cExcelGet.php] class cExcelGet { // 共通変数宣言 private $strFilePath; // ファイルフルパス名退避 // エクセル用カラム名 private $arrColName = array( // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM","AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ", "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM","BN","BO","BP","BQ","BR","BS","BT","BU","BV","BW","BX","BY","BZ", ); // ワークシートオブジェクト取得 private $objWorksheet; private $intLine; // データ行数 private $intColMax; // カラムMAX数 private $intRowMax; // 行MAX数 // コンストラクタ // [引数] $_strFilePath string : ファイルフルパス名 public function __construct ($_strFilePath) { // ファイルフルパス名を退避 $this->strFilePath = $_strFilePath; } // ファイルオープン // [戻り値] :true:正常、false:エラー public function open() { // ファイル存在チェック if (!file_exists($this->strFilePath)) { // ファイル存在エラー return false; } // エクセルファイル読込オブジェクト $objReader = PHPExcel_IOFactory::createReader("Excel2007"); // PHPExcelオブジェクト取得 $objPHPExcel = $objReader->load($this->strFilePath); // ワークシートオブジェクト取得 $this->objWorksheet = $objPHPExcel->getActiveSheet(); // カラムMAX取得 $strColMax = $this->objWorksheet->getHighestColumn(); // カラム文字列 $this->intColMax = PHPExcel_Cell::columnIndexFromString($strColMax); // 行MAX取得 $this->intRowMax = $this->objWorksheet->getHighestRow(); // データ行数 $this->intLine = 0; // 正常 return true; } // カラムMAX取得 public function getColMax() { return $this->intColMax; } // 1行データ取得 // [戻り値] :データが存在した場合は配列データ // (array("A" => "aaa", "B" => "bbbb")の様にカラム文字列でアクセス可能 ) // :false:行最終 public function getLine() { // データ行数 $this->intLine++; if ($this->intLine > $this->intRowMax) { // 処理行数がMAXを超えた場合 return false; } // 1行データ取得・行指定 $arrData = $this->getLineDirect($this->intLine); // データ配列を返す return $arrData; } // 1行データ取得・行指定 // [引数] $_intLine : 行番号(PHPExcelでは行は1~) // [戻り値] :データが存在した場合は配列データ // (array("A" => "aaa", "B" => "bbbb")の様にカラム文字列でアクセス可能 ) // :false:行最終 public function getLineDirect($_intLine) { $arrData = array(); for($c = 0; $c < $this->intColMax; $c++) { //colは [0] 始まりで [0] = "A" となる(rowは [1] 始まり) $arrData[$c] = $this->objWorksheet->getCellByColumnAndRow($c, $_intLine)->getValue(); if (is_null($arrData[$c])) { $arrData[$c] = ""; } else { $arrData[$c] = trim($arrData[$c]); } // 変換後のキーと値で設定 $arrData[$this->arrColName[$c]] = $arrData[$c]; } // データ配列を返す return $arrData; } } ?>
このクラスを使って以下のエクセルを読込んでみます。<?php // クラスファイル読込 require_once 'cExcelGet.php'; // [cExcelGet]クラスの生成 $insXlsx = new cExcelGet("ctest1.xlsx"); // ファイルオープン if ($insXlsx->open() == true) { // 1行データ取得 while ($arrData = $insXlsx->getLine()) { $str = ""; for ($i = 0; $i < $insXlsx->getColMax() ; $i++) { if ($str != "") $str .= ","; $str .= $arrData[$i]; } $str .= "<br>\n"; echo $str; } } else { echo "open error."; } ?>
これを実行するとブラウザに以下の様に表示されます。AAAA,BBBBB,CCC,DD 123,2000,4000,500 ABC001,B001,5000,140 C001,D002,600,200
このクラスを少し改良して、CSVファイルの場合に使用できる様にします。 尚 PHPExcel ライブラリのCSVファイル処理を利用します。(以下の記事を参照して下さい)
⇒PHP PHPExcel CSVファイルの読み込み・書き込みについて
上記の記事から、CSVファイルを読込んで PHPExcelオブジェクト を取得すれば、今回のクラスを親クラスとして利用できることが分かります。
それでは、その前に元のクラスを以下の様に変更します。<?php // Excelライブラリ読込 require_once './PHPExcel-1.8/Classes/PHPExcel.php'; // Excelファイル読込クラス class cExcelGet { // 共通変数宣言 protected $strFilePath; // ファイルフルパス名退避 // エクセル用カラム名 private $arrColName = array( // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM","AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ", "BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM","BN","BO","BP","BQ","BR","BS","BT","BU","BV","BW","BX","BY","BZ", ); // ワークシートオブジェクト取得 protected $objWorksheet; private $intLine; // データ行数 private $intColMax; // カラムMAX数 private $intRowMax; // 行MAX数 // コンストラクタ // [引数] $_strFilePath string : ファイルフルパス名 public function __construct ($_strFilePath) { // ファイルフルパス名を退避 $this->strFilePath = $_strFilePath; } // ファイルオープン // [戻り値] :true:正常、false:エラー public function open() { // ファイル存在チェック if (!file_exists($this->strFilePath)) { // ファイル存在エラー return false; } // エクセルファイル読込、ワークシートオブジェクト取得 $this->openWorksheet(); // カラムMAX取得 $strColMax = $this->objWorksheet->getHighestColumn(); // カラム文字列 $this->intColMax = PHPExcel_Cell::columnIndexFromString($strColMax); // 行MAX取得 $this->intRowMax = $this->objWorksheet->getHighestRow(); // データ行数 $this->intLine = 0; // 正常 return true; } // エクセルファイル読込、ワークシートオブジェクト取得 protected function openWorksheet() { // エクセルファイル読込オブジェクト $objReader = PHPExcel_IOFactory::createReader("Excel2007"); // PHPExcelオブジェクト取得 $objPHPExcel = $objReader->load($this->strFilePath); // ワークシートオブジェクト取得 $this->objWorksheet = $objPHPExcel->getActiveSheet(); } // カラムMAX取得 public function getColMax() { return $this->intColMax; } // 1行データ取得 // [戻り値] :データが存在した場合は配列データ // (array("A" => "aaa", "B" => "bbbb")の様にカラム文字列でアクセス可能 ) // :false:行最終 public function getLine() { // データ行数 $this->intLine++; if ($this->intLine > $this->intRowMax) { // 処理行数がMAXを超えた場合 return false; } // 1行データ取得・行指定 $arrData = $this->getLineDirect($this->intLine); // データ配列を返す return $arrData; } // 1行データ取得・行指定 // [引数] $_intLine : 行番号(PHPExcelでは行は1~) // [戻り値] :データが存在した場合は配列データ // (array("A" => "aaa", "B" => "bbbb")の様にカラム文字列でアクセス可能 ) // :false:行最終 public function getLineDirect($_intLine) { $arrData = array(); for($c = 0; $c < $this->intColMax; $c++) { //colは [0] 始まりで [0] = "A" となる(rowは [1] 始まり) $arrData[$c] = $this->objWorksheet->getCellByColumnAndRow($c, $_intLine)->getValue(); if (is_null($arrData[$c])) { $arrData[$c] = ""; } else { $arrData[$c] = trim($arrData[$c]); } // 変換後のキーと値で設定 $arrData[$this->arrColName[$c]] = $arrData[$c]; } // データ配列を返す return $arrData; } } ?>クラスの中で、子クラスから参照される変数と、子クラスによりオーバーライドされるメソッドを protected として宣言します。 そこで、protected の部分を作成しCSVファイル読込クラスを宣言します。
<?php // CSVファイル読込クラス(エクセル読込クラスから派生) class cCsvGet extends cExcelGet { // コンストラクタ // [引数] $_strFilePath string : ファイルフルパス名 public function __construct ($_strFilePath) { parent::__construct($_strFilePath); } protected function openWorksheet() { // CSV読込クラス生成 $objReader = new PHPExcel_Reader_CSV(); // CSVファイルの文字コード:Shift-JIS $objReader->setInputEncoding('SJIS'); // 区切り記号(カンマ) $objReader->setDelimiter(','); // 文字列の囲み文字(") $objReader->setEnclosure('"'); // シートの位置 $objReader->setSheetIndex(0); // 読込の結果としてPHPExcelオブジェクトが返る $objPHPExcel = $objReader->load($this->strFilePath); // ワークシートオブジェクト取得 $this->objWorksheet = $objPHPExcel->getActiveSheet(); } } ?>
このクラスを使って以下のCSVファイルを読込んでみます。("ctest1.csv"ファイル)aaaaaaaaaa,bbbbbb,cccccccc,dd 123,456,1000,2000 a01,b01,2000 c02,d03,500,600
以下が読込を実行するソースです。
<?php // クラスファイル読込 require_once 'cExcelGet.php'; require_once 'cCsvGet.php'; // [cCsvGet]クラスの生成 $insCsv = new cCsvGet("ctest1.csv"); // ファイルオープン if ($insCsv->open() == true) { while ($arrData = $insCsv->getLine()) { $str = ""; for ($i = 0; $i < $insCsv->getColMax() ; $i++) { if ($str != "") $str .= ","; $str .= $arrData[$i]; } $str .= "<br>\n"; echo $str; } } else { echo "open error."; } ?>これを実行するとブラウザに以下の様に表示されます。
aaaaaaaaaa,bbbbbb,cccccccc,dd 123,456,1000,2000 a01,b01,2000, c02,d03,500,600
以上、有用性があると言いましたが、特に使い勝手が良くないかもしれませんので、改良して使って頂ければと思います。
-
以下の記事で、クラス(class)の使い方について説明しましたが、その時は親クラスのメソッドを、 子クラスで同じメソッド名で宣言することでオーバーライドができることを記しました。
⇒PHP クラス(class)の使い方について
そこで、今回はクラス(class)のオーバーライドの使い方について更に詳しく説明します。
子クラスでオーバーライドしたメソッドですが、親クラスから呼出すことができます。
これは、少し変な感じですが、子クラスでインスタンスを生成し、 そのインスタンスから子クラスのオーバーライド・メソッドを呼出している親クラスのメソッドを呼び出せます。 取敢えず、簡単な例を以下に示します。<?php // 継承の基となる親クラス class cParent { // テスト関数1 public function func1() { echo "cParent_func1<br>\n"; $this->func2(); // 「テスト関数2」実行 } // テスト関数2 public function func2() { echo "cParent_func2<br>\n"; } } // [cParent]から派生した子クラス class cChild extends cParent { // オーバーライド・テスト関数2 public function func2() { echo "cChild_func2<br>\n"; } } // [cParent]クラスの生成 $insParent = new cParent(); // テスト関数1の実行 $insParent->func1(); // [cChild]クラスの生成 $insChild = new cChild(); // テスト関数1の実行 $insChild->func1(); ?>
親クラスに「func1()」「func2()」のメソッドを宣言し、「func1()」の中で自分の「func2()」を呼出しています。 また、親クラスから派生した子クラスに「func2()」というメソッドをオーバーライド宣言しています。
親クラスを生成し「func1()」を実行し、子クラスを生成し「func1()」を実行しています。
これを実行するとブラウザに以下の様に表示されます。cParent_func1 cParent_func2 cParent_func1 cChild_func2
子クラスを生成し「func1()」を実行した場合は、親クラスの「func2()」を実行するのではなく、 子クラスの「func2()」が実行されています。オーバーライドの結果が出ていると思います。
子クラスでオーバーライドすることで、親クラスの元の性質と異なる処理を宣言できます。
異なる子クラスを宣言すれば、親は一緒でも異なる処理を実行するクラスの宣言ができます。以下のソースを見て下さい。
<?php // 継承の基となる親クラス class cParent { // テスト関数1 public function func1() { echo "cParent_func1<br>\n"; $this->func2(); } // テスト関数2 public function func2() { echo "cParent_func2<br>\n"; } } // [cParent]から派生した子クラスその1 class cChild1 extends cParent { // オーバーライド・テスト関数2 public function func2() { echo "cChild1_func2<br>\n"; } } // [cParent]から派生した子クラスその2 class cChild2 extends cParent { // オーバーライド・テスト関数2 public function func2() { echo "cChild2_func2<br>\n"; } } // [cChild1]クラスの生成 $insChild1 = new cChild1(); // テスト関数1の実行 $insChild1->func1(); // [cChild2]クラスの生成 $insChild2 = new cChild2(); // テスト関数1の実行 $insChild2->func1(); ?>これを実行するとブラウザに以下の様に表示されます。
cParent_func1 cChild1_func2 cParent_func1 cChild2_func2
さらに、子クラスの中で、親クラスの処理のも必要な場合は parent:: を使って親クラスのメソッドを呼び出します。<?php // 継承の基となる親クラス class cParent { // テスト関数1 public function func1() { echo "cParent_func1<br>\n"; $this->func2(); } // テスト関数2 public function func2() { echo "cParent_func2<br>\n"; } } // [cParent]から派生した子クラスその1 class cChild1 extends cParent { // オーバーライド・テスト関数2 public function func2() { parent::func2(); echo "cChild1_func2<br>\n"; } } // [cParent]から派生した子クラスその2 class cChild2 extends cParent { // オーバーライド・テスト関数2 public function func2() { parent::func2(); echo "cChild2_func2<br>\n"; } } // [cChild1]クラスの生成 $insChild1 = new cChild1(); // テスト関数1の実行 $insChild1->func1(); // [cChild2]クラスの生成 $insChild2 = new cChild2(); // テスト関数1の実行 $insChild2->func1(); ?>これを実行するとブラウザに以下の様に表示されます。cParent_func1 cParent_func2 cChild1_func2 cParent_func1 cParent_func2 cChild2_func2
-
今回はクラス(class)の使い方について説明します。
クラスと言えば、オブジェクト指向型のデータ処理と言われていますが、 そこまで固く考えなくても、ある処理を行うにあたって必要なデータや関数をまとめたものと言えると思います。
クラスの宣言としては以下の様に行います。(実際の処理では無く日本語で記述しています)class クラス名 { // プロパティの宣言(外部から操作可能) public $変数名[ = 値]; // 内部プロパティの宣言(外部から操作できない) private $変数名[ = 値]; // メソッドの宣言 public function メソッド名(){ メソッド内処理... } // 内部メソッドの宣言 private function メソッド名(){ メソッド内処理... } // コンストラクタ(クラス生成時に呼ばれる関数) function __construct() { クラスの初期処理 } // デストラクタ(クラス破棄時に呼ばれる関数) function __destruct() { クラスの終了処理 } }
プロパティの宣言は public, private でしますが public 宣言されたプロパティは、 クラスの外部からの参照が可能で private 宣言されたプロパティは、クラス内でのみ参照できます。
また、メソッド宣言も同様で public 宣言されたメソッドは、クラスの外部からの呼出しができますが、 private 宣言されたメソッドは、クラス内でのみ呼出しできます。
ここで示した、コンストラクタ及びデストラクタはそれぞれ、クラスのインスタンス生成時及び、破棄時に呼び出される関数で、 必要無ければ宣言する必要はありません。
- 簡単な クラス の宣言例
- クラスの 継承(extends) の使い方の例
- プロパティの アクセス権(public, protected, private) について
- メソッドの アクセス権(public, protected, private) について
- オーバーライド の使い方の例
- コンストラクタ、デストラクタでの オーバーライド の注意点
■簡単なクラス の宣言例
「クラス」宣言とそのクラスを生成し実行する処理を1個のファイルの中で実現しています。 (実際問題としては、クラスの宣言のみを別ファイルにし、それを利用するファイルの先頭で include などで取り込むこともできます。)
以下のソースでは名前用のクラスとして「nameClass」として宣言しています。 プロパティの宣言として「姓名」の「姓」と「名」の部分に分けて退避できる様にし、 「姓名」としてのフル名称を取得するメソッドの宣言を行っています。 (このクラスは特に有用なものではありませんので悪しからず...)
更に、コンストラクタで「姓」と「名」に分けて引数で与える様にしています。 コンストラクタはクラスのインスタンスを生成する場合に new 命令の後にクラス名を記述し、 そのクラス名のカッコの中に引数を記述します。<?php // 名前用のクラス class nameClass { // プロパティの宣言 public $familyName = ""; public $lastName = ""; // メソッドの宣言 public function getFullName(){ return $this->familyName." ".$this->lastName; } // コンストラクタ() function __construct($_familyName, $_lastName) { // クラスの初期処理 $this->familyName = $_familyName; $this->lastName = $_lastName; } } // [nameClass]クラスの生成 $clsName = new nameClass("Tanaka", "Taro"); // フル名のメソッド呼出 $strName = $clsName->getFullName(); // 表示 echo "FullName:".$strName."<br>\n"; // ブラウザ表示 //FullName:Tanaka Taro ?>上記のメソッドの宣言、及びコンストラクタの中で $this が出てきていますが、これは自分自身のオブジェクト(インスタンス)を示すものです。 クラス内の変数やメソッドを参照する場合には $this の後にアロー演算子の -> を用いてアクセスします。
アロー演算子はインスタンスに対するものですので、クラスを生成した後でそのメソッドを呼び出す場合にも用います。
クラスのインスタンスから直接内部の変数がアクセスできるのは嫌な場合は、変数アクセス用のプロパティ設定メソッドを作成し、以下の様にします。 また、クラスのインスタンス生成時に引数の値が指定できない場合も在ると思いますので、コンストラクタの引数に省略できるデフォルト引数値を用いています。// 名前用のクラス class nameClass { // プロパティの宣言 private $familyName; private $lastName; // プロパティ用メソッドの宣言 public function setFamilyName($_familyName){ $this->familyName = $_familyName; } public function setLastName($_lastName){ $this->lastName = $_lastName; } // フル名前を返すメソッドの宣言 public function getFullName(){ return $this->familyName." ".$this->lastName; } // コンストラクタ(デフォルト引数) function __construct($_familyName = "", $_lastName = "") { // クラスの初期処理(メソッドを使ってみました) $this->setFamilyName($_familyName); $this->setLastName($_lastName); } } // [nameClass]クラスの生成 $clsName = new nameClass(); // プロパティ用のメソッド呼出 $clsName->setFamilyName("Tanaka"); $clsName->setLastName("Taro"); // フル名のメソッド呼出 $strName = $clsName->getFullName(); // 表示 echo "FullName:".$strName."<br>\n"; // ブラウザ表示 //FullName:Tanaka Taro■クラスの 継承(extends) の使い方の例
継承 とは基となるクラスの性質を引き継いで、さらに機能を増やしたい場合に使う方法です。
クラスを宣言する時に extends で親クラスを指定します。
以下の例は親クラスとして「cName」を宣言し、それを継承したクラス「cPerson」を宣言しています。
クラス「cPerson」は、クラス「cName」で宣言されたプロパティ、メソッドを全て引き継ぎ、 さらに「cPerson」内で宣言されたプロパティ、メソッドをものを持ちます。
// 継承の基となる親クラス:[cName] class cName { // プロパティの宣言 public $familyName = ""; public $lastName = ""; // メソッドの宣言 public function getFullName(){ return $this->familyName." ".$this->lastName; } } // [cName]から派生した子クラス:[cPerson] class cPerson extends cName { // プロパティの宣言 public $address = ""; // メソッドの宣言 public function getAddress(){ return $this->address; } } // [cPerson]クラスの生成 $insPerson = new cPerson(); // 親クラスのプロパティ設定 $insPerson->familyName = "Tanaka"; $insPerson->lastName = "Taro"; // 子クラスのプロパティ設定 $insPerson->address = "Tokyo"; // フル名のメソッド呼出,表示 echo "FullName:".$insPerson->getFullName()."<br>\n"; // 住所取得のメソッド呼出,表示 echo "Address:".$insPerson->getAddress()."<br>\n"; // ブラウザ表示 //FullName:Tanaka Taro //Address:Tokyo■プロパティの アクセス権(public, protected, private) について
プロパティのアクセス権の指定ですが public, protected, private の種類があります。
PHP の公式の説明によりますと「 public 宣言されたクラスのメンバーには、どこからでもアクセス可能です。 protected 宣言されたメンバーには、 そのクラス自身、そのクラスを継承したクラス、および親クラスからのみアクセスできます。 private 宣言されたメンバーには、そのメンバーを定義したクラスからのみアクセスできます。 」と記されています。
以下に アクセス権(public, protected, private) の例を示します。<?php class cAccess { // プロパティの宣言 public $_pub = "public"."<br>\n"; protected $_pro = "protected"."<br>\n"; private $_pri = "private"."<br>\n"; // メソッドの宣言 public function echoAll(){ echo "public:" .$this->_pub; echo "protected:".$this->_pro; echo "private:" .$this->_pri; } } // [cAccess]クラスの生成 $insAcc = new cAccess(); // プロパティ参照,表示 echo "public:" .$insAcc->_pub; echo "protected:".$insAcc->_pro; // エラーが発生する echo "private:" .$insAcc->_pri; // エラーが発生する // メソッド呼出 $insAcc->echoAll(); ?>これを実行するとブラウザに以下の様にエラーが表示されます。
public:public Fatal error: Cannot access protected property cAccess::$_pro in C:\xampp\htdocs\_test\class4.php on line 21
そこで21行目をコメントにして実行すると以下の様にエラーが表示されます。
public:public Fatal error: Cannot access private property cAccess::$_pri in C:\xampp\htdocs\_test\class4.php on line 22
クラスの外側から protected, private と宣言されたものはアクセスができないので、 さらに22行目をコメント化して再度実行すると以下の様な表示となります。
public:public public:public protected:protected private:private
そこでクラス「cAccess」から派生した「cAccess2」を宣言し、そのメソッドの中で、 「cAccess」の protected 宣言のプロパティがアクセスできることを示します。<?php class cAccess { // プロパティの宣言 public $_pub = "public"."<br>\n"; protected $_pro = "protected"."<br>\n"; private $_pri = "private"."<br>\n"; // メソッドの宣言 public function echoAll(){ echo "echoAll...<br>\n"; echo "public:" .$this->_pub; echo "protected:".$this->_pro; echo "private:" .$this->_pri; } } class cAccess2 extends cAccess { // メソッドの宣言 public function echoAll2(){ echo "echoAll2...<br>\n"; echo "public:" .$this->_pub; echo "protected:".$this->_pro; // アクセス可能 echo "private:" .$this->_pri; // 未定義のNotice警告!! } } // [cAccess2]クラスの生成 $insAcc2 = new cAccess2(); // 親クラスメソッド呼出 $insAcc2->echoAll(); // メソッド呼出 $insAcc2->echoAll2(); ?>これを実行するとブラウザに以下の様に警告が表示されますが protected 宣言のプロパティがアクセスできることが分かります。
echoAll... public:public protected:protected private:private echoAll2... public:public protected:protected Notice: Undefined property: cAccess2::$_pri in C:\xampp\htdocs\_test\class5.php on line 25 private:
■メソッドの アクセス権(public, protected, private) について
クラスメソッドのアクセス権においてもプロパティ同様 public, protected, private の種類があります。 アクセス権を明示せずに宣言したメソッドは public となります。
<?php class cAccess { // publicメソッドの宣言 public function pubFunc(){ echo "public...<br>\n"; } // protectedメソッドの宣言 protected function proFunc(){ echo "protected...<br>\n"; } // privateメソッドの宣言 private function priFunc(){ echo "private...<br>\n"; } function Func(){ $this->pubFunc(); $this->proFunc(); $this->priFunc(); } } // [cAccess]クラスの生成 $insAcc = new cAccess(); // クラスメソッド呼出 $insAcc->pubFunc(); $insAcc->proFunc(); // エラー発生!! $insAcc->priFunc(); // エラー発生!! $insAcc->Func(); ?>これを実行するとブラウザに以下の様にエラーが表示されます。
public... Fatal error: Call to protected method cAccess::proFunc() from context '' in C:\xampp\htdocs\_test\class6.php on line 28
そこで28行目をコメントにして実行すると以下の様にエラーが表示されます。
public... Fatal error: Call to private method cAccess::priFunc() from context '' in C:\xampp\htdocs\_test\class6.php on line 29
クラスの外側から protected, private と宣言されたメソッドはアクセスができないので、 さらに29行目をコメント化して再度実行すると以下の様な表示となります。
クラス内部のメソッドでは全てのメソッドがアクセス可能です。public... public... protected... private...
■オーバーライド(public function) の使い方の例
プロパティ(変数)、メソッド(関数)は同じ名前を子クラスに定義すれば、親クラスのプロパティ(変数)、メソッド(関数)を上書きすることができます。
この上書きができることで子クラスでは、親クラスとは異なる動作をさせることができます。以下にその例を示します。<?php // 継承の基となる親クラス class cName { // プロパティの宣言 public $familyName = ""; public $lastName = ""; // メソッドの宣言 public function getFullName(){ return $this->familyName." ".$this->lastName; } } // [cName]から派生した子クラス class cPerson extends cName { // メソッドの宣言 public function getFullName(){ return "FullName:".$this->familyName." ".$this->lastName; } } // [cPerson]クラスの生成 $insPerson = new cPerson(); // 親クラスのプロパティ設定 $insPerson->familyName = "Tanaka"; $insPerson->lastName = "Taro"; // 子クラスのメソッド呼出,表示 echo $insPerson->getFullName()."<br>\n"; // ブラウザ表示 //FullName:Tanaka Taro ?>子クラスの「getFullName()」メソッドは親クラスのものを上書きしており、メソッドを呼び出すと親クラスのメソッドは呼び出されず 子クラスのメソッドが呼び出されます。
尚、子クラスの「getFullName()」メソッドは親クラスのものを呼出して処理することもできます。
子クラスから親クラスのメソッドを呼び出す場合には parent:: を使います。上記のソースを一部変更します。<?php // 継承の基となる親クラス class cName { // プロパティの宣言 public $familyName = ""; public $lastName = ""; // メソッドの宣言 public function getFullName(){ return $this->familyName." ".$this->lastName; } } // [cName]から派生した子クラス class cPerson extends cName { // メソッドの宣言 public function getFullName(){ return "FullName:".parent::getFullName(); } } // [cPerson]クラスの生成 $insPerson = new cPerson(); // 親クラスのプロパティ設定 $insPerson->familyName = "Tanaka"; $insPerson->lastName = "Taro"; // フル名のメソッド呼出,表示 echo $insPerson->getFullName()."<br>\n"; ?>■コンストラクタ、デストラクタでの オーバーライド の注意点
コンストラクタ、デストラクタもオーバーライドが出来るのですが、少し注意が必要です。取敢えず以下のソースを見て下さい。
親クラスと子クラスを宣言していますが、中身はコンストラクタ、デストラクタの処理のみを行います。
<?php // 継承の基となる親クラス class cParent { // コンストラクタ function __construct() { echo "cParent__construct<br>\n"; } // デストラクタ function __destruct() { echo "cParent__destruct<br>\n"; } } // [cParent]から派生した子クラス class cChild extends cParent { // コンストラクタ function __construct() { echo "cChild__construct<br>\n"; } // デストラクタ function __destruct() { echo "cChild__destruct<br>\n"; } } // [cParent]クラスの生成 $insParent = new cParent(); // [cParent]クラスの廃棄 unset($insParent); // [cChild]クラスの生成 $insChild = new cChild(); // [cChild]クラスの廃棄 unset($insChild); ?>これを実行するとブラウザに以下の様に表示されます。
子クラスの生成時に、子クラスのコンストラクタのみが呼び出され、親クラスのコンストラクタは呼び出されません。
また、子クラスの廃棄時に、子クラスのデストラクタのみが呼び出され、親クラスのデストラクタは呼び出されません。
cParent__construct cParent__destruct cChild__construct cChild__destruct
子クラスは親クラスから派生しているので、当然、親クラスのコンストラクタ、デストラクタを呼出したいことはよくあります。
そこで、子クラスのコンストラクタ、デストラクタの中で、親クラスのコンストラクタ、デストラクタを呼出してやります。以下のソースをを見て下さい。<?php // 継承の基となる親クラス class cParent { // コンストラクタ function __construct() { echo "cParent__construct<br>\n"; } // デストラクタ function __destruct() { echo "cParent__destruct<br>\n"; } } // [cParent]から派生した子クラス class cChild extends cParent { // コンストラクタ function __construct() { parent::__construct(); echo "cChild__construct<br>\n"; } // デストラクタ function __destruct() { parent::__destruct(); echo "cChild__destruct<br>\n"; } } // [cChild]クラスの生成 $insChild = new cChild(); // [cChild]クラスの廃棄 unset($insChild); ?>これを実行するとブラウザに以下の様に表示されます。
cParent__construct cChild__construct cParent__destruct cChild__destruct