-
以下のページではPHPのクラス(Class)に存在しない プロパティ へのアクセスが可能になる様に マジックメソッド の __get(), __set(), __isset(), __unset() を宣言してクラスを拡張しました。
⇒PHP クラス(Class)のプロパティの使い方について(__get(), __set())
さて、このクラスに配列データをそのままプロパティとして設定する関数を追加します。
この関数では、配列データの キー をプロパティ名、 データ をプロパティの値として設定します。 (処理の実体は自分の中の __set() メソッドを利用します。)<?php class test { // 宣言していないプロパティ退避用配列 private $arrProp = array(); public function __get($name) { // 退避配列にデータが存在するか? if (isset($this->arrProp[$name])) { // データを返す return $this->arrProp[$name]; } else { return NULL; } } public function __set($name, $value) { // 退避配列にデータを設定 $this->arrProp[$name] = $value; } public function __isset($name) { // 退避配列内の存在チェック return isset($this->arrProp[$name]); } public function __unset($name) { if (isset($this->arrProp[$name]) == true) { // 退避配列内のunset unset($this->arrProp[$name]); } } // 配列のデータをプロパティ的に退避 public function setArray($arr) { if (is_array($arr)) { foreach ($arr as $key => $val) { $this->__set($key, $val); } } } } // クラス生成 $obj = new test(); // テスト用配列 $arrTest = array("prop1" => 100, "prop2" => "ABCDE", "prop3" => array("111", "222", "333")); // テスト用配列をプロパティ的に退避 $obj->setArray($arrTest); // プロパティとして取得 echo "<pre>"; var_dump($obj->prop1); var_dump($obj->prop2); var_dump($obj->prop3); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。 プロパティ「$prop1」「$prop2」「$prop3」の値が設定されていることが分かります。
int(100) string(5) "ABCDE" array(3) { [0]=> string(3) "111" [1]=> string(3) "222" [2]=> string(3) "333" }
配列をプロパティ的に使う例としては、データベースのテーブルの1レコードの内容をプロパティとして退避する場合があると思います。 以下にその例を示します。
あるデータベースに「test」テーブルが存在し、主キーとして「id」があるとします。その「id = 1」の1行データを取得することにします。 このソースの前にはデータベースへの接続が在りますが、今回は割愛してあります。 (ソース上は「$db」に接続後のPDOインスタンスが生成されたとしています)<?php ... // クラス生成(クラスのソースはこの前で読込済みとする) $obj = new test(); // SQL文を準備:「:id」がプレースホルダー $sql = 'SELECT * FROM test WHERE id = :id'; // PDOStatementクラスのインスタンス生成 $pre = $db->prepare($sql); // SQL文の「:id」を「1」に置き換え $pre->bindValue(':id', 3, PDO::PARAM_INT); // プリペアドステートメントを実行する $pre->execute(); // PDO::FETCH_ASSOCは、テーブルカラム名をキーとして連想配列にデータを取得 $row = $pre->fetch(PDO::FETCH_ASSOC); if ($row) { // テーブル行データ配列をプロパティ的に退避 $obj->setArray($arrTest); // この後でカラム名でプロパティとしてアクセスできる $w = $obj->XXXXXX; // XXXXXX:カラム名 } ... ?>この結果 $obj->XXXXXX の様にしてテーブルのカラム名でデータが取得できる様になります。
各テーブルごとにこの「test」クラスを基底としたクラスを作成し、その中でレコード取得関数を作り setArray を行えば 各テーブルクラスのインスタンスからカラム名のプロパティでカラムデータが取得できる様になると思います。
PR -
今回はPHPのクラス(Class)の プロパティ について説明したいと思います。
クラスの プロパティ はそのクラスの内部で必要な属性を保存しておくための変数として使用します。 プロパティ の宣言は private 及び public で行います。 public で宣言したプロパティは、外部から直接アクセスができますが private で宣言したプロパティは、外部から直接アクセスができないため、値を設定したり、取得する関数を別に用意します。
また、宣言されていないプロパティをアクセスした時に呼ばれる関数(マジックメソッド)が在りますので、 それを使った対処方法を以下に順次記します。
- 簡単な プロパティ の宣言例
- 存在しない プロパティ へのアクセス例
- 存在しない プロパティ へのアクセス例その2(設定)
- マジックメソッド での存在しない プロパティ へのアクセス制御(__get(), __set())
- マジックメソッド での存在しない プロパティ へのアクセス制御その2(__isset(), __unset())
■簡単な プロパティ の宣言例
テスト用クラスとして test を宣言しその中に1個のプロパティ $prop1 を宣言します。
このクラスを生成し、プロパティを var_dump 関数で直接アクセスします。<?php // テストクラス class test { public $prop1; } // クラス生成 $obj = new test(); // プロパティへのアクセス var_dump($obj->prop1); ?>これを実行するとブラウザに以下の様に表示されます。クラス生成後「$prop1」には何も設定されていので「NULL」と表示されます。
NULL
■存在しない プロパティ へのアクセス例
以下の例は上の例と似ていますが、宣言されていないプロパティ $prop2 へのアクセスを行います。
<?php // テストクラス class test { public $prop1; } // クラス生成 $obj = new test(); // 宣言されていないプロパティへのアクセス var_dump($obj->prop2); ?>これを実行するとブラウザに以下の様に表示されます。
Notice: Undefined property: test::$prop2 in xxxxx on line 9 NULL
(xxxxx:この部分は実際のソースの位置なので伏字にしました)
PHPのエラーメッセージが Notice となっていて、その後に NULL が表示されているので、どうも $prop2 が存在している様な感じです。
そこでソースの最後に、クラスのインスタンスオブジェクトそのものを表示してみます。<?php // テストクラス class test { public $prop1; } // クラス生成 $obj = new test(); // 宣言されていないプロパティへのアクセス var_dump($obj->prop2); ?>これを実行するとブラウザに以下の様に表示されます。クラスのインスタンス内には $prop2 は存在しない様です。 Notice の後の NULL はプロパティが存在しないので、仮に NULL が返された様です。
Notice: Undefined property: test::$prop2 in xxxxx on line 9 object(test)#1 (1) { ["prop1"]=> NULL }■存在しない プロパティ へのアクセス例その2(設定)
今度は存在しない プロパティ へ直接上書き設定を行っています。
<?php // テストクラス class test { public $prop1; } // クラス生成 $obj = new test(); // 宣言されていないプロパティへのアクセス(強制設定) $obj->prop2 = "2"; $obj->prop3 = "3"; // クラスインスタンスの表示 echo "<pre>"; var_dump($obj); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。宣言されていないプロパティへの設定は強制的に作成される様です。
これは仕様の様なので仕方無いのですが、微妙な感じです。 この微妙さを解消する為にPHPには宣言されていないプロパティをアクセスした時に呼ばれるメソッドをクラス内に宣言するころで 自分で対処できる様です。object(test)#1 (3) { ["prop1"]=> NULL ["prop2"]=> string(1) "2" ["prop3"]=> string(1) "3" }■マジックメソッド での存在しない プロパティ へのアクセス制御(__get(), __set())
PHPには宣言されていないプロパティをアクセスした時に呼ばれるメソッド名が決まっていまして、 プロパティ値の取得・設定用にそれぞれ __get() 、 __set() を宣言します。 以下にその例を示します。
<?php class Test { public $prop1; public function __get($name) { echo "__get($name)プロパティエラー
"; } public function __set($name, $value) { echo "__set($name, $value)プロパティエラー
"; } } // クラス生成 $obj = new test(); // 宣言されていないプロパティへのアクセス(強制設定) $w = $obj->prop2; $obj->prop2 = "2"; ?>これを実行するとブラウザに以下の様に表示されます。
__get(prop2)プロパティエラー __set(prop2, 2)プロパティエラー
この例では、宣言されていないプロパティへのアクセスでエラーを表示しているだけですので、 これを少し修正して、プロパティを内部に連想配列として退避することで、プロパティの動きを作ります。 以下にその修正版を示します。
取得用の __get() では退避配列にデータが存在すればその値を返し、無ければ NULL を返しています。 また設定用の __set() では退避配列にデータを退避するだけです。<?php class test { public $prop1; // 宣言していないプロパティ退避用配列 private $arrProp = array(); public function __get($name) { // 退避配列にデータが存在するか? if (isset($this->arrProp[$name])) { // データを返す return $this->arrProp[$name]; } else { return NULL; } } public function __set($name, $value) { // 退避配列にデータを設定 $this->arrProp[$name] = $value; } } echo "<pre>"; // クラス生成 $obj = new test(); // 宣言されていないプロパティへのアクセス(取得) var_dump($obj->prop2)."
"; // 宣言されていないプロパティへのアクセス(設定) $obj->prop2 = "2"; // 宣言されていないプロパティへのアクセス(再取得) var_dump($obj->prop2)."
"; var_dump($obj)."
"; echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。 配列「$arrProp」にプロパティ「prop2」が格納されています。
今回 __get() で配列にデータが無い場合には NULL を返していますが、 Exception でエラーを返した方が良い場合があると思います。NULL string(1) "2" object(test)#1 (2) { ["prop1"]=> NULL ["arrProp":"test":private]=> array(1) { ["prop2"]=> string(1) "2" } }
■マジックメソッド での存在しない プロパティ へのアクセス制御その2(__isset(), __unset())
マジックメソッド である __get() 、 __set() を宣言することで 宣言されていないプロパティをアクセスできる様になりました。
但し、以下の様にそのプロパティの存在チェックを isset() 関数で行うと思った様になりません。<?php class test { public $prop1; // 宣言していないプロパティ退避用配列 private $arrProp = array(); public function __get($name) { // 退避配列にデータが存在するか? if (isset($this->arrProp[$name])) { // データを返す return $this->arrProp[$name]; } else { return NULL; } } public function __set($name, $value) { // 退避配列にデータを設定 $this->arrProp[$name] = $value; } } // クラス生成 $obj = new test(); // プロパティ存在確認 if (isset($obj->prop2) == true) { echo "プロパティ存在OK"."これを実行するとブラウザに以下の様に表示されます。
"; } else { echo "プロパティ存在NG"."
"; } // プロパティ設定 $obj->prop2 = "2"; // プロパティ存在確認 if (isset($obj->prop2) == true) { echo "プロパティ存在OK"."
"; } else { echo "プロパティ存在NG"."
"; } ?>プロパティ存在NG プロパティ存在NG
これは、よくよく考えてみれば、__set() でプロパティ値として退避しているのは 「$arrProp」なのでこの中の存在をチェックしなければ、意味が無いことが分かります。
尚、マジックメソッド として宣言できるものの中に __isset() 、 __unset() があるのですが これらはクラスのプロパティに対して isset() 、 unset() を行う時に呼ばれるメソッドです。
よって、これらを宣言し、クラス内の「$arrProp」を処理する様に修正します。
<?php class test { public $prop1; // 宣言していないプロパティ退避用配列 private $arrProp = array(); public function __get($name) { // 退避配列にデータが存在するか? if (isset($this->arrProp[$name])) { // データを返す return $this->arrProp[$name]; } else { return NULL; } } public function __set($name, $value) { // 退避配列にデータを設定 $this->arrProp[$name] = $value; } public function __isset($name) { // 退避配列内の存在チェック return isset($this->arrProp[$name]); } public function __unset($name) { if (isset($this->arrProp[$name]) == true) { // 退避配列内のunset unset($this->arrProp[$name]); } } } // クラス生成 $obj = new test(); // プロパティ存在確認 if (isset($obj->prop2) == true) { echo "プロパティ存在OK"."これを実行するとブラウザに以下の様に表示されます。
"; } else { echo "プロパティ存在NG"."
"; } // プロパティ設定 $obj->prop2 = "2"; // プロパティ存在確認 if (isset($obj->prop2) == true) { echo "プロパティ存在OK"."
"; } else { echo "プロパティ存在NG"."
"; } ?>プロパティ存在NG プロパティ存在OK
これでクラス内で宣言していないプロパティを外部から任意の名前でアクセスができるクラスを作成できました。 このクラスを基底クラスとして、拡張したクラスを作成していけると思います。
ただし、任意の時点でプロパティが作成できることは、あちらこちらでその処理を行うと、 後からソースを見た時に理解に時間が掛かるかもしれません。 この辺りは、プロパティの仕様をしっかりしないと、クラス内に個別にプロパティを宣言した方が良かったことになりかねませんので。
-
今回は PhpSpreadsheet でエクセルファイルをPHPの配列への「読み込み」について説明したいと思います。
PhpSpreadsheet のワークシートオブジェクトにはシート内に存在する全てのセルのデータをPHPの配列へ読み込む rangeToArray 関数があります。 この関数を使えば、特に気にしなくてもセルの表示される値が取得できます。
■エクセルファイルの「読み込み」その1(セルは値のみ設定)
処理の手順は以下の通りです。
- 最初に IOFactory::load() メソッドで既存エクセルファイルを読込みSpreadsheetオブジェクト作成します。
- Spreadsheetオブジェクトの getSheet() メソッドでワークシートオブジェクトを取得します。
- ワークシートオブジェクトの calculateWorksheetDimension() メソッドでシート全体の領域を示す文字列を取得します。 (この関数は結果として "A1:[最大カラム文字列][最大行]" を返します。)
- ワークシートオブジェクトの rangeToArray() メソッドで全体のセルの値を配列に取得します。
<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Worksheet; // [test11.xlsx] ファイルをロードしSpreadsheetオブジェクト作成 $objSpreadsheet = IOFactory::load('./test11.xlsx'); // ワークシートオブジェクトの取得 $objSheet = $objSpreadsheet->getSheet(0); // ワークシート内の最大領域座標("A1:XXXnnn" XXX:最大カラム文字列, nnn:最大行) $strRange = $objSheet->calculateWorksheetDimension(); // ワークシートの全てのデータ取得(配列データとして) $arrData = $objSheet->rangeToArray($strRange); echo "<pre>"; print_r($arrData); echo "</pre>"; ?>読み込むエクセルファイルは以下のものを使います。
ブラウザの表示は以下の様な感じになります。(エクセル上で空白のセルは、配列の結果としても空白になります。)Array ( [0] => Array ( [0] => No [1] => DATA1 [2] => DATA2 [3] => DATA3 [4] => DATA4 ) [1] => Array ( [0] => 1 [1] => AAAAAAA [2] => BBB [3] => CCC [4] => DDDD ) [2] => Array ( [0] => 2 [1] => aaaa [2] => bbb [3] => ccc [4] => ) [3] => Array ( [0] => 3 [1] => ああああ [2] => いいい [3] => 漢字データ [4] => aaaa ) [4] => Array ( [0] => 4 [1] => [2] => [3] => [4] => ) )■エクセルファイルの「読み込み」その2(セルに計算式を含む場合)
上記のエクセルファイルの読み込みソースで、以下の様なセルに計算式を含むものがあるものを読込ませてみます。
尚、ソース上で「IOFactory::load('./test11.xlsx');」のファイルの部分を「'./test11-2.xlsx'」とします。
ブラウザの表示は以下の様な感じになります。(金額の計算結果が値として配列に設定されています。)Array ( [0] => Array ( [0] => No [1] => 商品名 [2] => 単価 [3] => 数量 [4] => 金額 ) [1] => Array ( [0] => 1 [1] => 商品1 [2] => 1000 [3] => 10 [4] => 10000 ) [2] => Array ( [0] => 2 [1] => 商品ああ [2] => 100 [3] => 5 [4] => 500 ) [3] => Array ( [0] => 3 [1] => 商品い [2] => 300 [3] => 6 [4] => 1800 ) [4] => Array ( [0] => 4 [1] => 商品う [2] => 500 [3] => 1 [4] => 500 ) )■エクセルファイルの「読み込み」内容をHTMLのTABLE表示
それでは上記で使用したエクセルファイル「'./test11-2.xlsx'」を読込んで HTML の TABLE タグを使って表形式での表示を行います。
<?php // ライブラリ読込 require '../vendor/autoload.php'; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Worksheet; // [test11-2.xlsx] ファイルをロードしSpreadsheetオブジェクト作成 $objSpreadsheet = IOFactory::load('./test11-2.xlsx'); // ワークシート・オブジェクトの取得 $objSheet = $objSpreadsheet->getSheet(0); // ワークシート内の最大領域座標("A1:XXXnnn" XXX:最大カラム文字列, nnn:最大行) $strRange = $objSheet->calculateWorksheetDimension(); // ワークシートの全てのデータ取得(配列データとして) $arrData = $objSheet->rangeToArray($strRange); ?> <html> <head> <meta charset="utf-8"> <title>test excel array </title> </head> <body> <table border="1"> <thead> <?php $arrWK = $arrData[0]; ?> <tr> <?php for ($ii = 0; $ii <= (count($arrWK) - 1); $ii++) { ?> <th><?php echo $arrWK[$ii]; ?></th> <?php } ?> </tr> </thead> <tbody> <?php for ($i = 1; $i <= (count($arrData) - 1); $i++) { $arrWK = $arrData[$i]; ?> <tr> <?php for ($ii = 0; $ii <= (count($arrWK) - 1); $ii++) { ?> <td><?php echo $arrWK[$ii]; ?></td> <?php } ?> </tr> <?php } ?> </tbody> </table> </body> </html>ブラウザには以下の様に表示されます。
-
配列(array) は「連想配列」であり、その宣言等については以下のページで説明しましたが、 いざ 配列 の使い道は何があるのかは初心者の方には分かりづらいと思います。
⇒PHP 配列(array)の使い方について(「添字配列」「連想配列」)
それで今回は 配列 を使って $_POST[] のデータを配列に取得する方法を説明します。
$_POST[] はウエブページから入力データを PHP に渡す一般的な方法です。
例えば、以下の様な HTML ページが在ったとします。 (「名前」「年齢」「メモ」の項目を入力し SUBMIT ボタンで「arr-post.php」に遷移させます)<html> <head> <meta charset="utf-8"> <title>test array post</title> </head> <body> <form name="test" action="arr-post.php" method="post"> <p>名前:</p><input type="text" name="name" /> <p>年齢:</p><input type="text" name="age" /> <p>メモ:</p><input type="text" name="memo" /> <input type="submit" value="送信" /> </form> </body> </html>
この form タグの遷移先の test.php での $_POST[] の取得は個別に行えば以下の様になります。
各項目ごとに $_POST[] にデータが存在することを確認し、個別の変数に値を設定します。<?php // $_POST["name"] 取得 $strName = ""; if ((isset($_POST["name"]) == true) && ($_POST["name"] != "")) { $strName = $_POST["name"]; } // $_POST["age"] 取得 $strAge = ""; if ((isset($_POST["age"]) == true) && ($_POST["age"] != "")) { $strAge = $_POST["age"]; } // $_POST["memo"] 取得 $strMemo = ""; if ((isset($_POST["memo"]) == true) && ($_POST["memo"] != "")) { $strMemo = $_POST["memo"]; } // 取得データ表示 echo "名前:".$strName."<br />"; echo "年齢:".$strAge."<br />"; echo "メモ:".$strMemo."<br />"; ?>
渡されるデータの個数が少なければこれでもいのですが、数が増えるとソース記述量も増えますので $_POST[] のキー値と、そのデータを格納する配列を導入します。
<?php // $_POST のキー値 $arrKey = array("name", "age", "memo"); // データ格納用配列の初期化 $arrPara = array(); // $_POST のキー値を順次処理する foreach($arrKey as $strKey) { // 各キー毎の格納用配列の初期化 $arrPara[$strKey] = ""; // $_POST の存在チェック if ((isset($_POST[$strKey]) == true) && ($_POST[$strKey] != "")) { // $_POST に存在すれば値を退避 $arrPara[$strKey] = $_POST[$strKey]; } } // 取得データの表示 foreach($arrPara as $strKey => $strPara) { echo "\$arrPara[".$strKey."] = ".$strPara."<br />"; } ?>
このままでもいいのですが、データが文字列として扱うのか、それとも数値として扱うのかを区別したり、 また、文字列データの場合には文字数制限を行ったりできる様にします。
1個のデータのキーに対して、複数の属性を持つことになりますので、属性データも配列で持ちます。
<?php // $_POST のキー値 $arrKey = array( "name" => array("title" => "名前", "attr" => "string", "maxlength" => 10) , "age" => array("title" => "年齢", "attr" => "integer", "maxlength" => 3 , "min" => 0, "max" => 99) , "memo" => array("title" => "メモ", "attr" => "string", "maxlength" => 20) , ); ?>
"title" はデータのタイトル、"attr" はデータ属性、"maxlength" は文字列の最大長で、"min","max" は数値の場合の最大最小値のチェック用です。
この属性配列を使って $_POST[] からデータを取得しながらエラーチェックを行う処理は以下の様になります。
<?php // $_POST のキー値 $arrKey = array( "name" => array("title" => "名前", "attr" => "string", "maxlength" => 10) , "age" => array("title" => "年齢", "attr" => "integer", "maxlength" => 3 , "min" => 0, "max" => 99) , "memo" => array("title" => "メモ", "attr" => "string", "maxlength" => 20) , ); // データ格納用配列の初期化 $arrPara = array(); // エラーメッセージ $strError = ""; // $_POST のキー値を順次処理する foreach($arrKey as $strKey => $arrAttr) { switch ($arrAttr["attr"]) { case "string": $arrPara[$strKey] = ""; if ((isset($_POST[$strKey]) === true) || ($_POST[$strKey] === "")) { $arrPara[$strKey] = $_POST[$strKey]; // 文字列長チェック if (mb_strlen($arrPara[$strKey]) > $arrAttr["maxlength"]) { $strError .= $arrAttr["title"].":データ長エラー<br />"; } } break; case "integer": $arrPara[$strKey] = ""; if ((isset($_POST[$strKey]) === true) || ($_POST[$strKey] === "")) { $arrPara[$strKey] = $_POST[$strKey]; // 文字列長チェック if (mb_strlen($arrPara[$strKey]) > $arrAttr["maxlength"]) { $strError .= $arrAttr["title"].":データ長エラー<br />"; } elseif (is_numeric($arrPara[$strKey]) === false) { // 数値チェックエラー $strError .= $arrAttr["title"].":数値チェックエラー<br />"; } else { // 最小最大値チェック $intAge = intval($arrPara[$strKey]); if ($intAge < $arrAttr["min"] || $arrAttr["max"] < $intAge) { $strError .= $arrAttr["title"].":最小最大値チェックエラー<br />"; } } } break; } } // 取得データの表示 foreach($arrPara as $strKey => $strPara) { echo "\$arrPara[".$strKey."] = ".$strPara."<br />"; } // エラー表示 if ($strError != "") { echo "<br />".$strError; } ?>
ラジオボタン、チェックボックス、セレクトボックス(コンボボックス)などのデータ属性はは考慮していませんので、 皆さんで拡張して下さい。
$_POST[] からデータを取得し配列に格納する処理は行ってきましたが、 それぞれのデータを別の変数に格納する場合にはどうするのかと言いますと、 以下の様に属性配列に格納先変数を 「参照変数」 として記述します。
<?php // 各データ用変数 $strName = ""; $strAge = ""; $strMemo = ""; // $_POST のキー値 $arrKey = array( "name" => array("title" => "名前", "attr" => "string", "save" =>&$strName , "maxlength" => 10) , "age" => array("title" => "年齢", "attr" => "integer", "save" =>&$strAge , "maxlength" => 3 , "min" => 0, "max" => 99) , "memo" => array("title" => "メモ", "attr" => "string", "save" =>&$strMemo , "maxlength" => 20) , ); // エラーメッセージ $strError = ""; // $_POST のキー値を順次処理する foreach($arrKey as $strKey => $arrAttr) { switch ($arrAttr["attr"]) { case "string": $arrAttr["save"] = ""; if ((isset($_POST[$strKey]) === true) || ($_POST[$strKey] === "")) { $arrAttr["save"] = $_POST[$strKey]; // 文字列長チェック if (mb_strlen($arrAttr["save"]) > $arrAttr["maxlength"]) { $strError .= $arrAttr["title"].":データ長エラー<br />"; } } break; case "integer": $arrAttr["save"] = ""; if ((isset($_POST[$strKey]) === true) || ($_POST[$strKey] === "")) { $arrAttr["save"] = $_POST[$strKey]; // 文字列長チェック if (mb_strlen($arrAttr["save"]) > $arrAttr["maxlength"]) { $strError .= $arrAttr["title"].":データ長エラー<br />"; } elseif (is_numeric($arrAttr["save"]) === false) { // 数値チェックエラー $strError .= $arrAttr["title"].":数値チェックエラー<br />"; } else { // 最小最大値チェック $intAge = intval($arrAttr["save"]); if ($intAge < $arrAttr["min"] || $arrAttr["max"] < $intAge) { $strError .= $arrAttr["title"].":最小最大値チェックエラー<br />"; } } } break; } } // 取得データの表示(この処理も属性配列から格納先データを参照) foreach($arrKey as $strKey => $arrAttr) { echo $arrAttr["title"]." = ".$arrAttr["save"]."<br />"; } // エラー表示 if ($strError != "") { echo "<br />".$strError; } ?>
-
今回はPHPのプログラムでは必ず使用するであろうデータ形式である 配列(array) について説明したいと思います。
配列(array) とは1個の変数の中に キー とそれに対応する 値 の組み合わせを複数持っているデータ構造です(リスト構造)。
この 値 の中に各種のデータ型を格納できます。別の配列を格納することで配列の入れ子ができます。
そもそも 配列(array) は何に使うのでしょうか?
配列の中に入れるデータはそれらが関連したデータで、ひとかたまりとして処理できるものです。
例えば以下の様な用途で使ってきました。- 固定的なオプションデータとして配列で持った方が良いデータ(例:一週間の"月"、"火"、"水"...の文字列の配列)
- 連続した数値データを持つ配列データ(数値データの配列から平均、標準偏差などの計算...)
- HTML出力用のSELECTタグ用のVALUE値と表示値の配列データ
- HTML出力用のOPTIONタグ用のVALUE値と表示値の配列データ
- $_POST、$_GET の値を格納するための配列
- データベースのテーブルから取得する一覧データのための配列
- CSVファイル、Excelファイルの読込結果のための配列
- 等々...(拾い上げると各種あります)
プログラムで処理するために繰り返し処理に向いているデータを配列として格納し、 各種の処理を行うことが配列を使う理由になります。
通常プログラム言語の「配列」は キー(添字) が数値(インデックス)である「添字配列」と、キー(添字) を文字列とする「連想配列」の2種類があります。
PHP では「添字配列」と「連想配列」の間に違いはなく、配列型は 1 つだけで、 同じ配列で整数のインデックスと文字列のインデックスを同時に使えます。
これは「添字配列」として使っていた配列が、組み方によっては「連想配列」が混在する様なことにもなりますので、注意が必要です。
インデックスを数値のみとして扱えば「添字配列」として処理でき、インデックスを文字列(数値も含む)で処理すれば「連想配列」として 処理できると考えられます。 (PHPの内部ではインデックスと値の組み合わせの「連想配列」として処理される)
【配列の構文:array()で指定】 $var = array( key1 => value1, key2 => value2, key3 => value3, ... ); ・$var :配列を格納する変数。 ・keyX :キー値(数値でも文字列でもOK) ・valueX:要素値(各種のデータで配列もOK)
それでは「添字配列」と「連想配列」の宣言例から使い方の説明を行います。- 添字配列 の宣言例
- 添字配列 の使い方の例
- 添字配列 の使い方の例その2(foreach文)
- 添字配列 の使い方の例その3(foreach文の注意)
- 添字配列 の使い方の例その4(角括弧構文で作成・修正)
- 連想配列 の宣言例
- 連想配列 の使い方の例その1(foreach文)
- 連想配列 の使い方の例その2(foreach文の注意)
- 連想配列 の使い方の例その3(角括弧構文で作成・修正)
■添字配列 の宣言例
「添字配列」として宣言するには array() の中でキー値の指定を省いて、要素値のみ連続して記述します。
以下のソースでは要素が数値のみの配列、要素が文字列のみの配列、要素が数値,文字列が混在の配列を定義しています。
それぞれを宣言した変数の内容を表示するために var_dump() 関数で処理します。 尚、 var_dump() 出力の前後を <pre> タグで囲むことで、 <br> タグ無しで改行出力をブラウザで改行した様にみられます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 要素が文字列のみの配列 $arr2 = array("10", "20", "30"); // 要素が数値,文字列が混在の配列 $arr3 = array("10", 20, "30"); echo "<pre>"; var_dump($arr1); var_dump($arr2); var_dump($arr3); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。
array(3) { [0]=> int(10) [1]=> int(20) [2]=> int(30) } array(3) { [0]=> string(2) "10" [1]=> string(2) "20" [2]=> string(2) "30" } array(3) { [0]=> string(2) "10" [1]=> int(20) [2]=> string(2) "30" }【var_dump の配列の出力形式】 array(n) { [i]=> int(d) ... [j]=> string(c) "contents" ... } ・array(n) :arrayで配列を示す(n:配列の要素数) ・[i], [j] :キー値(指標) ・int(d) :数値データ (d:要素値) ・string(c) :文字列データ(c:文字列数) ・"contents":文字列の値
■添字配列 の使い方の例
以下の例はよくある配列の反復処理です。 配列の指標を使って「0」から配列の最後の指標までをループで配列の内容を表示処理しています。
この例は必ず指標は「0」から始まり、指標の最後は「配列の要素数-1」であるのが前提です。
(尚、「配列の要素数」を取得するために count() 関数を使用します。)
しかし、この前提が違っているとプログラム実行でエラーが発生しますので、後からこれを回避する方法を記します。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 指標を使って「0」から「配列の大きさ-1」までを反復処理 for($i = 0; $i < count($arr1); $i++) { echo "\$arr1[".$i."]=".$arr1[$i]."<br />\n"; } ?>これを実行するとブラウザに以下の様に表示されます。
$arr1[0]=10 $arr1[1]=20 $arr1[2]=30
■添字配列 の使い方の例その2(foreach文)
配列を反復処理するため前述の for文 とは別の foreach文 があります。構文は以下の通りです。
【foreach文の構文】 foreach (array_expression as $value) 文; foreach (array_expression as $key => $value) 文; ・array_expression:配列(指定された配列の反復処理を行う) ・$value :配列の要素 ・$key :指標(キー値)
array_expression で指定した配列に 関して反復処理を行います。 配列に格納されている要素の値を先頭から $value に代入し、 配列の中身を指し示すポインタを先頭に設定し $value に代入します。この時ポインタが次の要素を示す様に一つ進められます。 これを順次処理することで、配列の要素を順次取得できます。
尚、2番目の形式は、さらに各反復で現在の要素のキーを変数 $key に代入します。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 配列の内容を順次取得する「foreach」を使って反復処理 foreach($arr1 as $i => $value) { echo "\$arr1[".$i."]=".$value."<br />\n"; } ?>これを実行するとブラウザに上記の様に表示されます。(ここでは表示割愛)
尚、指標の取得が必要無ければ「$i =>」の部分を記述しなくてもOKです。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 「foreach」で指標の取得無し foreach($arr1 as $value) { echo "DATA=".$value."<br />\n"; } ?>■添字配列 の使い方の例その3(foreach文の注意)
配列を反復処理で要素を変更したい場合には $value の前に &(アンドマーク) を記述します。
&(アンドマーク) を付加することで反復処理での $value には配列の要素のリファレンス(参照:C言語のポインタの様なもの)が渡されます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as &$value) { $value = $value * 10; // 要素を10倍する } unset($value); // 最後の要素への参照を解除します echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。配列の各要素が10倍されていることが分かります。
Array ( [0] => 100 [1] => 200 [2] => 300 )ここで注意が必要なのは unset($value); です。 ここで変数 $value を破棄しないと $value には $arr1 の3番目の要素 $arr1[2] への参照が残ったままで、 不用意に $value に値を設定したりすると $arr1[2] が書き変ってしまいます。
■添字配列 の使い方の例その4(角括弧構文で作成・修正)
配列に対して角括弧構文でキーを指定し要素値を設定することで、配列の更新をすることが出来ます。
キーを指定が無い場合は、指標の中で最大値の次の値を指標として値が追加されます。<?php // 要素が数値のみの配列 $arr1 = array(10, 20, 30); // 角括弧構文でキーを指定し配列の要素を更新 $arr1[2] = 100; // 角括弧構文でキー指定無しで配列の要素を追加 $arr1[] = 200; echo "<pre>"; print_r($arr1); echo "</pre>"; ?>
これを実行するとブラウザに以下の様に表示されます。
配列の3番目の要素が「100」に更新され、4番目の要素として「200」が追加されます。Array ( [0] => 10 [1] => 20 [2] => 100 [3] => 200 )尚、以下の様に角括弧構文のみで配列を作成することが出来ます。
最初の $arr1[] = で $arr1 が存在していなければ配列として生成され、キー「0」の要素に値が設定されます。
array() 宣言をコメントで消していますが、これがあれば明示的に配列だと宣言できます。(少し冗長なのですが、私はこちらを推奨します。)<?php // 配列宣言 //$arr1 = array(); // 角括弧構文でキー指定無しで配列の要素を追加 $arr1[] = 10; $arr1[] = 20; $arr1[] = 30; echo "<pre>"; print_r($arr1); echo "</pre>"; ?>
■連想配列 の宣言例
今までの 添字配列 ではキー値としていわゆるインデックスとしての数値でしたが、連想配列 としてはキー値に文字列等を用います。
宣言の最初はキーを文字列で行っていますが、最後は数値で宣言しています。<?php // 配列宣言 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, // キー:数値!! "KEY5" => "555", ); echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。キーが文字列であっても数値であっても、ちゃんと配列が生成されています。 宣言の中で最後の行でカンマを記述していますが、カンマ無しでもOKです。
Array ( [KEY1] => 11111 [KEY2] => 222 [KEY3] => 3333 [KEY4] => 44444 [0] => 100 [KEY5] => 555 )■連想配列 の使い方の例その1(foreach文)
添字配列 の時の様に foreach文 を使った例を示します。
<?php // 配列宣言 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, "KEY5" => "555", ); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as $key => $value) { echo "\$arr1[".$key."]=".$value."<br />\n"; } ?>これを実行するとブラウザに以下の様に表示されます。
$arr1[KEY1]=11111 $arr1[KEY2]=222 $arr1[KEY3]=3333 $arr1[KEY4]=44444 $arr1[0]=100 $arr1[KEY5]=555
■連想配列 の使い方の例その2(foreach文の注意)
添字配列のところで説明しましたが、連想配列でも配列を反復処理で要素を変更したい場合には $value の前に &(アンドマーク) を記述します。 (PHPの配列は連想配列として考えればどちらもおなじことですが)
&(アンドマーク) を付加することで反復処理での $value には配列の要素のリファレンス(参照:C言語のポインタの様なもの)が渡されます。<?php // 要素が数値のみの配列 $arr1 = array( "KEY1" => "11111", "KEY2" => "222", "KEY3" => "3333", "KEY4" => "44444", 0 => 100, "KEY5" => "555", ); // 配列の内容を順次取得する「foreach」を使ってループ処理 foreach($arr1 as &$value) { $value = $value . "AA"; // 要素に文字列 "AA" 付加 } unset($value); // 最後の要素への参照を解除します echo "<pre>"; print_r($arr1); echo "</pre>"; ?>これを実行するとブラウザに以下の様に表示されます。配列の各要素文字列 "AA" 付加されていることが分かります。
指標「0」の要素は数値でしたが、文字列との連結では数値が文字列 "100" に強制的に変換されて "AA" が付加されることになります。
array(6) { ["KEY1"]=> string(7) "11111AA" ["KEY2"]=> string(5) "222AA" ["KEY3"]=> string(6) "3333AA" ["KEY4"]=> string(7) "44444AA" [0]=> string(5) "100AA" ["KEY5"]=> string(5) "555AA" }ここで注意が必要なのは unset($value); です。 ここで変数 $value を破棄しないと $value には $arr1 の3番目の要素 $arr1["KEY5"] への参照が残ったままで、 不用意に $value に値を設定したりすると $arr1["KEY5"] が書き変ってしまいます。
■連想配列 の使い方の例その3(角括弧構文で作成・修正)
配列に対して角括弧構文でキーを指定し要素値を設定することで、配列の更新をすることが出来ます。
キーを指定が無い場合は、指標の中で最大値の次の値を指標として値が追加されます。
<?php // 配列宣言 $arr1 = array(); // 角括弧構文でキー指定で配列の要素を追加 $arr1["KEY1"] = "11111"; $arr1["KEY2"] = "222"; $arr1["KEY3"] = "3333"; $arr1["KEY4"] = "44444"; $arr1[0 ] = 100; $arr1["KEY5"] = "555"; // 配列内部表示 echo "<pre>最初の表示<br>"; var_dump($arr1); echo "</pre>"; // キー指定無しで追加 $arr1[] = 200; // 配列内部表示 echo "<pre>追加後の表示<br>"; var_dump($arr1); echo "</pre>"; ?>
これを実行するとブラウザに以下の様に表示されます。
キー指定無しでの配列への追加は、キーの中で数値の最大値に+1されたものがキーとなりその要素に値が設定されます。 (数値キーがなければキーは「0」となります。)
最初の表示 array(6) { ["KEY1"]=> string(5) "11111" ["KEY2"]=> string(3) "222" ["KEY3"]=> string(4) "3333" ["KEY4"]=> string(5) "44444" [0]=> int(100) ["KEY5"]=> string(3) "555" } 追加後の表示 array(7) { ["KEY1"]=> string(5) "11111" ["KEY2"]=> string(3) "222" ["KEY3"]=> string(4) "3333" ["KEY4"]=> string(5) "44444" [0]=> int(100) ["KEY5"]=> string(3) "555" [1]=> int(200) }