[2020/11/20] PHP コマンドライン実行時のプログラム引数($argv)の取得について (No.230)
[2020/11/16] PHP PHPExcel_Chart ワークシート上のチャートの軸の値の書式を設定する方法について (No.229)
[2020/10/20] PHP PHPExcel セル内の文字列のフォントサイズを変える方法について (No.228)
[2020/08/18] PHP クラス(Class)のプロパティの使い方についてその2(__get(), __set(), __isset(), __unset()) (No.226)
[2020/08/17] PHP クラス(Class)のプロパティの使い方について(__get(), __set()) (No.225)
-
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
-
今回はPHPのプログラムではそこまで使用頻度が多くは無いのですが、コマンドラインからPHPプログラムを実行する時に 指定された 引数 を取得する方法について説明したいと思います。
プログラムの引数を取得するにはPHPが設定した $argv という配列変数を参照します。
$argv と対になる変数として $argc がありますが、これは $argv の配列の個数が入っています。
(C言語を使ったことがれば、すぐに分かると思いますが、機能的にはほぼ同じものと考えられます。 $argc は $argv の count() を取れば分かるのですが…)■$argv の使用例
プログラムの中では $argv 変数を直接参照すればよく、以下のソースは var_dump により内容を表示させています。 取敢えず $argc 変数も表示しています。
<?php // $argvの内容表示 var_dump($argv); // $argcの内容表示 var_dump($argc); ?>
私の環境ではWindowsの xampp でPHPを導入し、DOSのコマンドプロンプトからの実行を行っています。 実行結果は以下の様に表示されます。
$argv の先頭のデータ([0]番目)は実行したプログラムのファイル名がフルパスで入っていて、 [1]番目のデータに最初の引数の文字列が、[2]番目のデータに2番目の引数の文字列が入っています。C:\>C:\xampp\php\php.exe C:\xampp\htdocs\_test\argv1.php aaaaaa bbbbbb array(3) { [0]=> string(31) "C:\xampp\htdocs\_test\argv1.php" [1]=> string(6) "aaaaaa" [2]=> string(6) "bbbbbb" } int(3)
■$argv の使用例その2
それでは $argv の内容をプログラム的に使用してみます。
以下の例は $argv の内容をそのまま表示する反復処理です。
<?php // $argvの引数部分の内容表示 for ($i = 1; $i <= ($argc - 1); $i++) { echo "{$i}番目のコマンドライン引数:".$argv[$i]."\n"; } ?>
これを実行すると以下の様に表示されます。見事に文字化けしています。
それもそのはずで、プログラムソースは UTF-8 で保存されていますが、WindowsのDOSプロンプトで実行しているためです。 Windowsでは Shift-JIS コードで出力しないと正常に表示されません。C:\>C:\xampp\php\php.exe C:\xampp\htdocs\_test\argv2.php aaaaaa bbbbbb 1逡ェ逶ョ縺ョ繧ウ繝槭Φ繝峨Λ繧、繝ウ蠑墓焚・啾aaaaa 2逡ェ逶ョ縺ョ繧ウ繝槭Φ繝峨Λ繧、繝ウ蠑墓焚・喘bbbbb
これを解消するには、表示文字列を Shift-JIS に変換する必要があります。そこで、以下の様になります。<?php // $argvの引数部分の内容表示 for ($i = 1; $i <= ($argc - 1); $i++) { // UTF-8 での文字列 $str = "{$i}番目のコマンドライン引数:".$argv[$i]."\n"; // Shift-JIS に変換して表示 echo mb_convert_encoding($str, "SJIS", "UTF-8"); } ?>
これを実行すると以下の様に表示され文字化けは解消されています。
プログラムがコマンドラインからのみの実行ならばこれでもいいのですが、もしブラウザからの実行と、コマンドラインからの実行の 両方に対応するには、すこし細工が必要になってきます。
ブラウザは UTF-8 のソースを実行する為に、C:\>C:\xampp\php\php.exe C:\xampp\htdocs\_test\argv3.php aaaaaa bbbbbb 1番目のコマンドライン引数:aaaaaa 2番目のコマンドライン引数:bbbbbb
尚、この $argv ですがコマンドラインから実行した時のみ存在する変数で、ブラウザからの実行ではエラーになります。http://localhost/_test/argv1.php
上のアドレスをブラウザから指定すると、以下のエラーが表示されます。
Notice: Undefined variable: argv in C:\xampp\htdocs\_test\argv1.php on line 3 NULL Notice: Undefined variable: argc in C:\xampp\htdocs\_test\argv1.php on line 5 NULL
PR -
今回は1個のチャート上に「Bar Chart:棒グラフ」を描画しますが、その時の軸の値の表示の書式を設定する方法を説明したいと思います。
おおまかな手順としては、軸オブジェクトクラス PHPExcel_Chart_Axis を生成し setAxisNumberProperties メソッドで書式を文字列で設定し、 軸オブジェクトをチャート生成時に軸の設定値に渡します。
元となるソースは以下の記事を引用しています。
⇒PHP PHPExcel_Chart ワークシート上にチャート(Bar Chart:棒グラフ)を作成する方法について
■チャートの軸の値の書式を設定
<?php // ライブラリ読込 require_once './PHPExcel-1.8/Classes/PHPExcel.php'; // PHPExcelオブジェクト作成 $objPHPExcel = new PHPExcel(); // ワークシートオブジェクト取得 $objWorksheet = $objPHPExcel->getActiveSheet(); // チャート用テストデータ生成 $objWorksheet->fromArray( array( array('年' , '商品売上'), array( 2016, 1200000), array( 2017, 850000), array( 2018, 710000), array( 2019, 1800000), array( 2020, 900000), ) ); // 系列ラベルの指定 $arrDataSeriesLabels1 = array( new PHPExcel_Chart_DataSeriesValues('String', 'Worksheet!$B$1', NULL, 1), //商品売上 ); // X軸ラベルの指定 $arrCategorysDataSeries = array( new PHPExcel_Chart_DataSeriesValues('String', 'Worksheet!$A$2:$A$6', NULL, 5), //2016 to 2020 ); // 商品1:描画データの指定 $arrDataSeriesValues1 = array( new PHPExcel_Chart_DataSeriesValues('Number', 'Worksheet!$B$2:$B$6', NULL, 5), //商品1 ); // 商品1:チャート・データシリーズの生成 $objSeries1 = new PHPExcel_Chart_DataSeries( PHPExcel_Chart_DataSeries::TYPE_BARCHART, // plotType PHPExcel_Chart_DataSeries::GROUPING_STANDARD, // plotGrouping range(0, count($arrDataSeriesValues1) - 1), // plotOrder $arrDataSeriesLabels1, // plotLabel $arrCategorysDataSeries, // plotCategory $arrDataSeriesValues1 // plotValues ); // プロットエリアにチャート・データシリーズに設定 $objPlotArea = new PHPExcel_Chart_PlotArea(NULL, array($objSeries1)); // レジェンド生成 $objLegend = new PHPExcel_Chart_Legend(PHPExcel_Chart_Legend::POSITION_TOPRIGHT, NULL, false); // チャート・タイトル生成 $objTitle = new PHPExcel_Chart_Title('Axis-Test'); // 軸オブジェクト $xAxis = new PHPExcel_Chart_Axis(); // 軸の値の書式(1000以下を省略) $xAxis->setAxisNumberProperties("#,##0,"); // チャート生成 $objChart = new PHPExcel_Chart( 'chart1', // name $objTitle, // title $objLegend, // legend $objPlotArea, // plotArea TRUE, // plotVisibleOnly 0, // displayBlanksAs NULL, // xAxisLabel NULL, // yAxisLabel $xAxis, // xAxis NULL // yAxis ); // ワークシート内のチャート位置設定 $objChart->setTopLeftPosition('A8'); // 左上 $objChart->setBottomRightPosition('G20'); // 右下 // ワークシートにチャート追加 $objWorksheet->addChart($objChart); // [test-g-4-1.xlsx]:Excel2007形式で保存する $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, "Excel2007"); $objWriter->setIncludeCharts(TRUE); $objWriter->save('test-g-8-1.xlsx'); exit(); ?>
出力されたエクセルファイル[test-g-8-1.xlsx]を見てみると以下の様になります。
この例では軸の値表示で1000以下の値を省略しています。
尚、チャート生成の new PHPExcel_Chart の xAxis にあたるところに軸オブジェクトを設定しています。 チャートの表示からすれば yAxis なのかなと思ったのですが、逆の様です。 (このあたりははっきりしないのですが、商品1の売上値は横方向に在るためそれで xAxis でしょうか? 後に解明できた時には記事を修正します。)
-
今回は PHPExcel でセルの中にフォントサイズが異なる文字列を設定する方法を説明したいと思います。
今まではセルに対して文字列をそのまま設定すれば、フォントサイズはデフォルトのままで設定できました。
セルに設定する値を文字列では無く、リッチテキストクラス「PHPExcel_RichText」を使うことで、 設定する文字列にフォントなどの指定ができます。<?php // ライブラリ読込 require_once './PHPExcel-1.8/Classes/PHPExcel.php'; // PHPExcelオブジェクト作成 $objBook = new PHPExcel(); // シート設定 $objSheet = $objBook->getActiveSheet(); // リッチテキストで前半はサイズ12で、後半はサイズ20で設定 $objRichText = new PHPExcel_RichText(); // リッチテキストに文字列設定 $objTextElm = $objRichText->createTextRun("サイズ12"); // フォントサイズ12設定 $objTextElm->getFont()->setSize(12); // リッチテキストに文字列追加設定 $objTextElm = $objRichText->createTextRun("サイズ20"); // フォントサイズ20設定 $objTextElm->getFont()->setSize(20); // [A1]セルに設定 $objSheet->getCell('A1')->setValue($objRichText); // ブラウザへの指定 $objWriter = PHPExcel_IOFactory::createWriter($objBook, "Excel2007"); $objWriter->save('test11-1.xlsx'); exit(); ?>
出力されたエクセルファイルを見てみると以下の様になります。
”サイズ12”の文字列はサイズ12で、”サイズ20”の文字列はサイズ20で設定されている様子がわかります。
-
以下のページでは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 を行えば 各テーブルクラスのインスタンスからカラム名のプロパティでカラムデータが取得できる様になると思います。
-
今回は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
これでクラス内で宣言していないプロパティを外部から任意の名前でアクセスができるクラスを作成できました。 このクラスを基底クラスとして、拡張したクラスを作成していけると思います。
ただし、任意の時点でプロパティが作成できることは、あちらこちらでその処理を行うと、 後からソースを見た時に理解に時間が掛かるかもしれません。 この辺りは、プロパティの仕様をしっかりしないと、クラス内に個別にプロパティを宣言した方が良かったことになりかねませんので。