-
以前 stdClass の使い方を以下の記事に記しましたが、今回はそれを関数の引数に使おうと思います。
⇒【PHP】連想配列の様な「stdClass」の使い方について
stdClass を引数にする場合には、どの様なプロパティを設定するのかは、前もって関数の呼び出し側と、関数内の処理を決めておく必要があります。
但し、引数が非常に多くなる場合には stdClass で渡すことですっきりした関数呼び出しにはなると思います。
以下のソースは stdClass を生成し3個のプロパティへを設定し、その内容を表示する簡単な例です。
<?php //[stdClass]が引数の関数宣言 function funcStd(stdClass $cls) { echo "stdVal1=[$cls->stdVal1]<br />"; echo "stdVal2=[$cls->stdVal2]<br />"; echo "stdVal3=[$cls->stdVal3]<br />"; } //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; $stdObj->stdVal3 = "3333"; //関数の実行(データ表示) funcStd($stdObj); ?>
3個のプロパティ値が表示されることが確認できます。stdVal1=[1111] stdVal2=[2222] stdVal3=[3333]
さらにもう一つの関数を宣言します。 この関数は、同じ引数を持つのですが各プロパティを再設定する様にしています。
<?php //[stdClass]が引数の関数宣言 function funcStd(stdClass $cls) { echo "stdVal1=[$cls->stdVal1]<br />"; echo "stdVal2=[$cls->stdVal2]<br />"; echo "stdVal3=[$cls->stdVal3]<br />"; } //[stdClass]の内容を変更する関数宣言 function funcStdUpd(stdClass $cls) { $cls->stdVal1 *= 10; $cls->stdVal2 = $cls->stdVal2 . "AAA"; $cls->stdVal3 = $cls->stdVal3 . "BBB"; } //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; $stdObj->stdVal3 = "3333"; //関数の実行(データ表示) funcStd($stdObj); //[stdClass]の内容を変更 funcStdUpd($stdObj); //関数の実行(データ表示) funcStd($stdObj); ?>
これを実行すると以下の様な結果になります。stdVal1=[1111] stdVal2=[2222] stdVal3=[3333] stdVal1=[11110] stdVal2=[2222AAA] stdVal3=[3333BBB]
関数の引数としてクラスを渡すと、参照渡しで行われる様です。 参照渡しのため、クラスプロパティの値を書き換えることが出来ますので、注意が必要です。
また、 stdClass にプロパティが存在するかどうかをチェックし、処理を分けることも可能です。 上のソースに4番目のプロパティの存在有無で処理を分ける様にする処理を付加したものを以下に示します。<?php //[stdClass]が引数の関数宣言 function funcStd(stdClass $cls) { echo "stdVal1=[$cls->stdVal1]<br />"; echo "stdVal2=[$cls->stdVal2]<br />"; echo "stdVal3=[$cls->stdVal3]<br />"; if(isset($cls->stdVal4)) { echo "stdVal4=[$cls->stdVal4]<br />"; } } //[stdClass]の内容を変更する関数宣言 function funcStdUpd(stdClass $cls) { $cls->stdVal1 *= 10; $cls->stdVal2 = $cls->stdVal2 . "AAA"; $cls->stdVal3 = $cls->stdVal3 . "BBB"; if(isset($cls->stdVal4)) { $cls->stdVal4 = $cls->stdVal4 . "CCC"; } } //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; $stdObj->stdVal3 = "3333"; //関数の実行(データ表示) funcStd($stdObj); //[stdClass]の内容を変更 $stdObj->stdVal4 = "4444"; funcStdUpd($stdObj); //関数の実行(データ表示) funcStd($stdObj); ?>
これを実行すると以下の様な結果になります。stdVal1=[1111] stdVal2=[2222] stdVal3=[3333] stdVal1=[11110] stdVal2=[2222AAA] stdVal3=[3333BBB] stdVal4=[4444CCC]
PR -
以前 stdClass について以下の記事を書きましたが、 このクラスですが、連想配列的に使えるので当然 foreach の処理が行えます。
⇒【PHP】連想配列の様な「stdClass」の使い方について<?php // [stdClass]の生成 $stdObj = new stdClass; $stdObj->Val1 = 1111; $stdObj->Val2 = "2222"; $stdObj->Val3 = "CCC"; echo "<pre>"; var_dump($stdObj); // [stdClass]を[foreach]で順次取得 foreach ($stdObj as $key => $val) { echo "stdObj[$key] => ".$val."<br />"; } echo "</pre>"; ?>
これを動作させると以下の様な表示になります。object(stdClass)#1 (3) { ["Val1"]=> int(1111) ["Val2"]=> string(4) "2222" ["Val3"]=> string(3) "CCC" } stdObj[Val1] => 1111 stdObj[Val2] => 2222 stdObj[Val3] => CCC
連想配列の様にキーとその値が取得できています。
stdClass 使いようによってはいろいろできそうに思います。
-
最近他の人が作ったプログラムの改修作業が在ったのですが、その中で stdClass を使っていて 私は使ったことが無かったので少し調べてみたところ、連想配列の様な使い方ができることを知りました。
クラスを使う場合、普通は別のクラス宣言でクラス名を付けますが stdClass は無名クラスとして クラスオブジェクトを生成する様です。
以下のソースは stdClass を生成し2個のプロパティへの代入を行う簡単な例です。
stdClass で生成されたオブジェクトに対して、プロパティを指定する時点で、 内部的にそのプロパティが生成されるようです。<?php //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; //[stdClass]の参照 echo "stdVal1=[$stdObj->stdVal1]
"; echo "stdVal2=[$stdObj->stdVal2]
"; ?>
結果は以下の表示になります。stdVal1=[1111] stdVal2=[2222]
2個のプロパティに値が設定されていることが確認できます。
尚、このソースに stdVal3 というプロパティを参照する様にしてみます。<?php //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; //[stdClass]の参照 echo "stdVal1=[$stdObj->stdVal1]
"; echo "stdVal2=[$stdObj->stdVal2]
"; echo "stdVal3=[$stdObj->stdVal3]
"; ?>
この結果は以下の様に、Notice エラーが発生します。
代入設定されていないプロパティを参照することはできない様です。stdVal1=[1111] stdVal2=[2222] Notice: Undefined property: stdClass::$stdVal3 in C:\xampp\htdocs\__test\test-stdclass.php on line 9 stdVal3=[]
この stdClass ですが配列に変換することができます。 以下のソースでは stdClass オブジェクトを array オブジェクトに代入し変換しています。<?php //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; //[stdClass]から[array]への変換 $arrObj = (array)$stdObj; echo "stdVal1=[".$arrObj["stdVal1"]."]
"; echo "stdVal2=[".$arrObj["stdVal2"]."]
"; ?>
上のソースから stdClass は連想配列的であることが分かります。
尚、 stdVal1 とソース上固定の記述のみしか扱えないわけでは無く、 次の例では stdVal1 の参照を変数を用いて行う方法を示します。<?php //[stdClass]の生成 $stdObj = new stdClass; $stdObj->stdVal1 = 1111; $stdObj->stdVal2 = "2222"; //[stdClass]の参照を変数で行う $key1 = "stdVal1"; $key2 = "stdVal2"; echo "stdVal1=[".$stdObj->$key1."]
"; echo "stdVal2=[".$stdObj->$key2."]
"; //中括弧で囲っても同じ echo "stdVal1=[".$stdObj->{$key1}."]
"; echo "stdVal2=[".$stdObj->{$key2}."]
"; ?>
オブジェクトのプロパティを変数で扱えると応用がいろいろ利くと思います。
PHP でシステムを組んでいると、データの中の区分値などを select タグを用いて入力します。 この区分値を入力不可にしようとして select タグの部分に disabled="disabled" とすることが多いです。
ただこの方法ですと、画面上は select ボックスは表示されるのですが POST 処理で値が渡ってきません。 以下のソースをブラウザで表示して OK を押下すると「select value = 」の所には何も表示されません。
-
PHP でシステムを組んでいると、データの中の区分値などを select タグを用いて入力します。 この区分値を入力不可にしようとして select タグの部分に disabled="disabled" とすることが多いです。
ただこの方法ですと、画面上は select ボックスは表示されるのですが POST 処理で値が渡ってきません。 以下のソースをブラウザで表示して OK を押下すると「select value = 」の所には何も表示されません。
<?php $strTestSel = isset($_POST['testsel']) ? $_POST['testsel'] : ''; ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> </head> <body> <h2>selcet test</h2> <span> select value = <?php echo($strTestSel); ?> </span> <form method="post" > <select name="testsel" disabled="disabled"> <option value=""></option> <option value="1">TEST1</option> <option value="2" selected="selected">TEST2</option> <option value="3">TEST3</option> </select> <br /> <input type="submit" value="OK"> </form> </body> </html>
select タグに disabled="disabled" とするのではなく option タグに選択されていないところを disabled="disabled" とし 選択されたいるところに selected="selected" とします。 上記のソースを以下の様に変更しました。
<?php $strTestSel = isset($_POST['testsel']) ? $_POST['testsel'] : ''; ?> <!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> </head> <body> <h2>selcet test</h2> <span> select value = <?php echo($strTestSel); ?> </span> <form method="post" > <select name="testsel"> <option value="" disabled="disabled"></option> <option value="1" disabled="disabled">TEST1</option> <option value="2" selected="selected">TEST2</option> <option value="3" disabled="disabled">TEST3</option> </select> <br /> <input type="submit" value="OK"> </form> </body> </html>
この様にするとドロップダウン表示をした時に selected="selected" とした option タグが通常の表示となり disabled="disabled" としたタグは選択できない灰色の表示になります。
-
データのグループ化(集計処理)を行う時には GROUP BY句 を使うことは、以下の記事で説明しました。
⇒MySQL データのグループ化(集計処理)について(GROUP BY句、WITH ROLLUP)
今回は、グループ化された結果データに対して条件付けの方法について説明します。 この条件を付けのために HAVING句 を使いますがその例と、さらに WHERE句 と同時に使った時の注意点について記します。
以下の内容で、順を追って説明します。■HAVING句の書き方ついて
HAVING句の書き方は以下の様な構文で指定します。
SELECT カラム名1 [, カラム名2, ...] ,[集計関数...] FROM テーブル名... GROUP BY カラム名1 [, カラム名2, ...] HAVING 条件式
GROUP BY の後ろに指定されたカラム名の値が同じデータのグループ化を行います。 複数のカラム名が指定された場合は、それぞれのカラム名の値が同じものでグループ化を行います。
HAVING句は は GROUP BY の後ろに「HAVING」に続いて条件式を記述します。 条件式はグループ化で使用したカラムに対しする条件や、集計関数を使った条件式となります。
テストデータとして「商品情報」と「売上データ」のテーブルを使い、テーブルの連結を行いながら、 グループ化について説明したいと思います。
これについては、最初に触れましたが、以下の記事のテーブルを使用します。
⇒MySQL データのグループ化(集計処理)について(GROUP BY句、WITH ROLLUP)
■HAVING句にグループ化のカラム名を使う例について
先ずは HAVING句 を使わずに売上データに対してグループ化を行う為に GROUP BY に1個のカラムとして「商品分類」を指定し、 「商品分類」ごとの商品の売上数と売上金額の合計数を表示する SQL を示します。
「商品分類」は「商品マスタ」に持っているため、「売上データ」と「商品マスタ」を FROM句 で INNER JOIN で結合します。SELECT tm_prod.class AS '商品分類', SUM(tt_sales.volume) AS '数量', SUM(tt_sales.amount) AS '金額' FROM tt_sales INNER JOIN tm_prod ON tm_prod.id = tt_sales.id_prd AND tm_prod.del = 0 GROUP BY tm_prod.class ORDER BY tm_prod.class;
この SQL の結果は以下の通りです。
+----------+------+-------+ | 商品分類 | 数量 | 金額 | +----------+------+-------+ | cre | 9 | 15000 | | era | 21 | 3650 | | kpen | 13 | 1620 | | pen | 58 | 4900 | +----------+------+-------+ 4 rows in set (0.00 sec)
それでは「商品分類」が「pen」の文字列を含むデータを抽出するため HAVING句 を以下の様に追加します。
SELECT tm_prod.class AS '商品分類', SUM(tt_sales.volume) AS '数量', SUM(tt_sales.amount) AS '金額' FROM tt_sales INNER JOIN tm_prod ON tm_prod.id = tt_sales.id_prd AND tm_prod.del = 0 GROUP BY tm_prod.class HAVING tm_prod.class LIKE '%pen%' ORDER BY tm_prod.class;
この SQL の結果は以下の通りです。
+----------+------+------+ | 商品分類 | 数量 | 金額 | +----------+------+------+ | kpen | 13 | 1620 | | pen | 58 | 4900 | +----------+------+------+ 2 rows in set (0.01 sec)
確かに「商品分類」に「pen」の文字列を含むデータのみが表示されました。
■HAVING句に集計関数を使う例について
今度は上記の集計 SQL に「金額」が4000円以上のデータを抽出するため HAVING句 を以下の様に追加します。
SELECT tm_prod.class AS '商品分類', SUM(tt_sales.volume) AS '数量', SUM(tt_sales.amount) AS '金額' FROM tt_sales INNER JOIN tm_prod ON tm_prod.id = tt_sales.id_prd AND tm_prod.del = 0 GROUP BY tm_prod.class HAVING SUM(tt_sales.amount) >= 4000 ORDER BY tm_prod.class;
この SQL の結果は以下の通りです。
+----------+------+-------+ | 商品分類 | 数量 | 金額 | +----------+------+-------+ | cre | 9 | 15000 | | pen | 58 | 4900 | +----------+------+-------+ 2 rows in set (0.02 sec)
■SQL文の中に WHERE句とHAVING句を共に使った場合について
集計 SQL では WHERE句 と HAVING句 を共に使った場合に、 先ず WHERE句 で対象となるデータを絞り込んで集計処理を行います。 その後で HAVING句 の条件を加味して最終的なデータが取得されます。
今回の例を示す前に「売上データ」の一覧を再度表示します。MariaDB [test]> select * from tt_sales; +----+--------+------------+--------+-------+--------+------+ | no | id_prd | salesdate | volume | price | amount | del | +----+--------+------------+--------+-------+--------+------+ | 1 | 1 | 2024-01-04 | 10 | 80 | 800 | 0 | | 2 | 4 | 2024-01-04 | 1 | 1000 | 1000 | 0 | | 3 | 6 | 2024-01-04 | 2 | 120 | 240 | 0 | | 4 | 7 | 2024-01-05 | 3 | 130 | 390 | 0 | | 5 | 1 | 2024-01-07 | 15 | 80 | 1200 | 0 | | 6 | 2 | 2024-01-07 | 10 | 100 | 1000 | 0 | | 7 | 5 | 2024-01-07 | 2 | 2000 | 4000 | 0 | | 8 | 1 | 2024-01-05 | 20 | 80 | 1600 | 0 | | 9 | 3 | 2024-01-05 | 1 | 100 | 100 | 0 | | 10 | 4 | 2024-01-10 | 2 | 1000 | 2000 | 0 | | 11 | 2 | 2024-01-15 | 2 | 100 | 200 | 0 | | 12 | 6 | 2024-01-05 | 5 | 120 | 600 | 0 | | 13 | 7 | 2024-01-14 | 3 | 130 | 390 | 0 | | 14 | 8 | 2024-01-20 | 1 | 150 | 150 | 0 | | 15 | 5 | 2024-01-20 | 4 | 2000 | 8000 | 0 | | 16 | 8 | 2024-01-22 | 10 | 150 | 1500 | 0 | | 17 | 9 | 2024-01-22 | 10 | 200 | 2000 | 0 | +----+--------+------------+--------+-------+--------+------+ 17 rows in set (0.00 sec)
WHERE句 での条件付けとして「売上日(salesdate)」の範囲を指定し、 さらに HAVING句 で「金額」の範囲を条件づけます。
「売上日(salesdate)」が「2024-01-05 ~ 2024-01-20」の範囲で、「金額」は4000円以上で、 以下の様な SQL となります。SELECT tm_prod.class AS '商品分類', SUM(tt_sales.volume) AS '数量', SUM(tt_sales.amount) AS '金額' FROM tt_sales INNER JOIN tm_prod ON tm_prod.id = tt_sales.id_prd AND tm_prod.del = 0 WHERE tt_sales.salesdate BETWEEN '2024-01-05' AND '2024-01-20' GROUP BY tm_prod.class HAVING SUM(tt_sales.amount) >= 4000 ORDER BY tm_prod.class;
この SQL の結果は以下の通りです。
+----------+------+-------+ | 商品分類 | 数量 | 金額 | +----------+------+-------+ | cre | 8 | 14000 | | pen | 48 | 4100 | +----------+------+-------+ 2 rows in set (0.03 sec)