-
今回は TCPDF で行う 「PDFファイル出力」 について説明したいと思います。
Webシステムでエクセルファイルやワードファイルのダウンロードは良くあることですが、 それらのファイルを見るためには、エクセルやワードのソフトが必要になります。
そこで PDF の出番ですが、上記のソフトが無くてもブラウザ上で見ることが出来る様になっていますので、 各種のデータ検索後のPDF出力の需要は結構あります。
このライブラリですが PHPでの 「PDFファイル出力」 と言えば TCPDF と推奨されています。
割と簡単に PDFファイル が作成できますので、使用されてみてはいかがでしょうか。
■TCPDF のダウンロードとインストール
TCPDF のダウンロードは以下の所から行えます。
【GitHub】tecnickcom / TCPDF
⇒https://github.com/tecnickcom/tcpdf画面上部の緑色の Code ボタンをクリックし更に Download ZIP をクリックででダウンロードが開始されます。
以下の様に HTML ドキュメントのフォルダに展開します。 私のテスト環境はWindows上の xampp で行いますので C:\xampp\htdocs\ フォルダの中に tcpdf フォルダを作成し TCPDF-main.zip を展開し、中身を tcpdf フォルダにコピーしました。(下図参照)■簡単なPDF表示
簡単なPDF表示処理として HTML 形式の内容をPDFとしてブラウザに表示させることを行います。 手順としては以下の様になります。
- TCPDF ライブラリの読込
- TCPDF クラスの生成
- TCPDF クラスへの新規ページ追加
- 日本語フォントの設定
- HTML文字列のブラウザへの表示
<?php // ライブラリ読込 require_once('../tcpdf/tcpdf.php'); // TCPDFクラス生成 $pdf = new TCPDF(); $pdf->setPrintHeader(false); // 新規ページ追加 $pdf->AddPage(); // デフォルトで用意されている日本語フォント[小塚ゴシックPro M] $pdf->SetFont("kozgopromedium", "", 10); // HTMLの定義 $html = <<< EOF <style> h1 { font-size: 24px; // 文字の大きさ color: #ff0000; // 文字の色 text-align: center; // テキストを真ん中に寄せる } p { font-size: 12px; // 文字の大きさ color: #000000; // 文字の色 text-align: left; // テキストを左に寄せる } </style> <h1>PDFテスト1</h1> <p>これは <b>TCPDF</b> を使った <b>PDF</b> の出力テストです。</p> EOF; // HTML書式で出力する $pdf->writeHTML($html); // PDF表示出力 $pdf->Output('pdf1.pdf', 'I'); // 'I':ブラウザに出力する(既定) ?>実行結果は以下の様な表示になるはずです。 HTML での表現をそのまま PDF として表示できますので、いろんなものが簡単に PDF 化できると思います。
TCPDF クラスの生成は引数無しで行っていますが、クラス生成の関数(__construct をみると)の引数は7個あり、以下の様になっています。public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false)- $orientation用紙の向き('P':ポートレート, 'L':ランドスケープ 規定値:'P')
- $unit測位単位('mm':ミリm, 'cm':センチm, 'pt':ポイント, 'in':インチ 規定値:'mm')
- $format用紙の大きさ('A4','A5','B5' などの用紙サイズを文字列指定 規定値:'A4')
- $unicode文字列がUNICODEかの指定(規定値:true)
- $encoding文字セットエンコーディング(htmlを戻すときに使用 規定値:true)
- $diskcache廃止された機能(規定値:false) この機能は内部的に使っていない
- $pdfa[PDF/A]モードを使う場合バージョンNO[1, 3]を指定(規定値:false [PDF/A]モード未使用)
TCPDF クラスの生成を引数ありで記述すれば以下の様になります。
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false, false);クラスの生成直後は TCPDF オブジェクトにはPDFのページが存在しませんので AddPage() メソッドで1ページ追加します。 ページを追加することで、そのページに対して出力処理が行える状態になります。
文字のフォントは規定値では helvetica になっていますので、これを日本語が表示出来る様に TCPDF に既に備わっている 日本語フォント[小塚ゴシックPro M:'kozgopromedium']を SetFont() メソッドで指定します。
次は HTML 文字列を作成しを writeHTML() メソッドで PDF のページに書き出します。
なお、HTMLのタグは以下のものがサポートされています。(実際のソースより)
Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul
最後に Output() メソッドで PDF をブラウザに出力します。public function Output($name='doc.pdf', $dest='I') // $name : 保存時のファイル名 // $dest : ドキュメントの出力先を指定 // 'I': ブラウザに出力する、ブラウザで保存する時のファイル名が $name で指定した名前になる。 // 'D': ブラウザでダウンロードする。ファイル名は $name で指定した名前になる。 // 'F': ローカルサーバーファイルとして保存する。ファイル名は $name で指定した名前になる。 // 'S': PDFドキュメントの内容を文字列として出力する。
■HTMLページからPDFを別タブで表示させる(A タグ)
上の例ではブラウザの URL アドレスに直接「http://localhost/_test_pdf/pdf1.php」などと入力し、そのタブでの PDF 表示を行いました。
ただし、URL を直接では無く HTML ページから間接的に指定して別タブで表示させることが出来ます。
A タグを使って以下の様にすれば、リンクをクリックすると別タブに PDF 出力が表示されます。<html> <head> <meta charset="utf-8"> <title>PDF - 1</title> </head> <body> <h2>PDF 出力を起動</h2> <a href="./pdf1.php" target="_blank">[pdf1.pdf]別タブで表示</a> </body> </html>
さらに、A タグをソースで記述では無く Javascript で行う場合は以下の様になります。<html> <head> <meta charset="utf-8"> <title>PDF - 1</title> <script type="text/javascript"> function showPdf() { var a = document.createElement("a"); document.body.appendChild(a); a.href = "./pdf1.php"; a.target = "blank"; a.click(); a.remove(); } </script> </head> <body> <h2>PDF 出力を起動</h2> <button onclick="showPdf();">[pdf1.pdf]別タブで表示</button> </body> </html>
PDF 出力とは直接関係はないことでしたが、出力処理だけで動作させることは少なく、起動の方法も必要かと思いここに記しました。
■HTMLページからPDFを別タブで表示させる・その2
上の例では A タグを使って別タブに PDF 出力を表示する方法でしたが、 PDF 出力プログラム側で引数が必要な場合、 A タグではブラウザの URL に引数がそのまま表示されてしまいます。
これを出ない様にするには POST する必要があります。
それでは以下に PDF 側に1個の引数を持つ様に変更して、それを呼出す HTML ファイルを記します。
PDF出力側
<?php require_once('../tcpdf/tcpdf.php'); // 引数の取得 $para = ""; if (isset($_POST["para"])) { $para = $_POST["para"]; } // TCPDFクラス生成 $pdf = new TCPDF(); $pdf->setPrintHeader(false); // 新しいpdfページを追加 $pdf->AddPage(); // デフォルトで用意されている日本語フォント[小塚ゴシックPro M] $pdf->SetFont("kozgopromedium", "", 10); // HTMLの定義 $html = <<< EOF <style> h1 { font-size: 24px; // 文字の大きさ color: #ff0000; // 文字の色 text-align: center; // テキストを真ん中に寄せる } p { font-size: 12px; // 文字の大きさ color: #000000; // 文字の色 text-align: left; // テキストを左に寄せる } </style> <h1>PDFテスト1</h1> <p>これは <b>TCPDF</b> を使った <b>PDF</b> の出力テストです。</p> <p>引数は <b>$para</b> です。</p> EOF; // HTML書式で出力する $pdf->writeHTML($html); // pdf表示設定 $pdf->Output('pdf1.pdf', 'I'); // 'I':ブラウザに出力する(既定) ?>PDF出力を呼出すHTML側
<html> <head> <meta charset="utf-8"> <title>PDF 1-3</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> function showPdf() { var form = document.createElement("form"); form.method = "POST"; form.action = "./pdf1-2.php"; form.target = "blank"; var hid = document.createElement("input"); hid.type = "hidden"; hid.name = "para"; hid.value = $("#para").val(); form.appendChild(hid); document.body.appendChild(form); form.submit(); form.remove(); } </script> </head> <body> <h2>PDF 出力を起動</h2> <input type="input" id="para" value="test" /> <button onclick="showPdf();">[pdf1.pdf]別タブで表示</button> </body> </html>
PR -
今回は、今更ながら each の使い方を再考してみます。
each には2種類の使い方があります。 ひとつは jQuery の セレクタ に対してのものと、もう一つは配列やコレクションやオブジェクトに対するものです。
共にそれぞれが内部に持っているものに対して、順次処理を行うことでは似た感じです。
先ずは jQuery の セレクタ に対しての each の書き方ですが、以下の様になります。$('セレクタ名').each(function([index[, element]]) { // index : 各要素のインデックス番号(値は 0 から始まる) // element : 繰り返し処理中の要素を参照 各要素に関する処理; });
これを使った例として以下に HTML ファイル側のソースを示します。■each を使った例
<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> //TEST関数 function testEach() { $('li').each(function(index, element) { console.log(index + ':' + $(element).text()); }); } </script> </head> <body> <h2>test each 1</h2> <li>ラベル1</li> <li>ラベル2</li> <li>ラベル3</li> <br /> <button onclick="javascript:testEach();">TEST</button> </body> </html>9行目の .each(function(index, element) { ... }); で each 処理を行っています。
処理は要素の index と element で取得できるテキスト値をコンソールに出力しています。(以下の様になります。)0: ラベル1 1: ラベル2 2: ラベル3
each の処理で index と element を記述せずに以下の様にしても、同様な処理が行えます。
以下の例では element の代わりに this を使っています。 特に index を使う必要が無ければ、いつもは this で記述することが多いです。
この this ですが、each の繰り返しの処理の中で、現在のセレクタ?(オブジェクト)を指し示す変数みたいなものと考えて良いと思います。<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> //TEST関数 function testEach() { $('li').each(function() { // index , elemnt を省略 console.log($(this).text()); }); } </script> </head> <body> <h2>test each 2</h2> <li>ラベル1</li> <li>ラベル2</li> <li>ラベル3</li> <br /> <button onclick="javascript:testEach();">TEST</button> </body> </html>
この例から少し発展させて <li> 要素がクリックされた時に、クリックされたラベル以外の文字列を表示する様に変更します。<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> // 初期処理 $(function(){ // li 要素のクリック時の処理 $('li').on('click', function() { // クリック時の[this]退避 var this_click = this; // li 要素の全てを処理 $('li').each(function() { if (this_click != this) { // クリック以外のラベル console.log($(this).text()); } }); }); }); </script> </head> <body> <h2>test each 2</h2> <li>ラベル1</li> <li>ラベル2</li> <li>ラベル3</li> </body> </html>
それでは、配列やコレクションやオブジェクトに対する each について説明します。 構文的には以下の様になります。
$.each(collection, function(index, value) { // collection : each処理の対象となる配列またはオブジェクト // function : 各繰り返し処理で実行したい関数を指定 // index : 配列であればインデックス番号、オブジェクトであればkey // value : 繰り返し処理中の値 各要素に関する処理; });
$.each で宣言された関数の中で、引数である index, value を利用することが出来ます。
以下に、配列データとオブジェクトの中身を全てコンソールに出力する例を示します。
■配列やコレクションやオブジェクトに対する each 例
<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> //TEST関数 function testEach() { // 配列 var arr = ['A001', 'B002', 'C003']; $.each(arr, function(index, value) { console.log('index(' + index + ') = ' + value); }); // オブジェクト var obj = { 'key1' : 'A001', 'key2' : 'B002', 'key3' : 'C003' }; $.each(obj, function(index, value) { console.log('index(' + index + ') = ' + value); }); } </script> </head> <body> <h2>test each 5</h2> <button onclick="javascript:testEach();">TEST</button> </body> </html>
コンソールの出力は以下の様になります。オブジェクトの場合 index にキーが渡されることがわかります。index(0) = A001 index(1) = B002 index(2) = C003 index(key1) = A001 index(key2) = B002 index(key3) = C003
今回の例でも、 index, value を記述せずに this を使うことが出来ます。
■配列やコレクションやオブジェクトに対する each 例
<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> //TEST関数 function testEach() { // 配列 var arr = ['A001', 'B002', 'C003']; $.each(arr, function() { console.log(this.valueOf()); // [PrimitiveValue]の値 //console.log(this + ""); // この方法でもOK }); // オブジェクト var obj = { 'key1' : 'A001', 'key2' : 'B002', 'key3' : 'C003' }; $.each(obj, function() { console.log(this.valueOf()); // [PrimitiveValue]の値 //console.log(this + ""); }); } </script> </head> <body> <h2>test each 6</h2> <button onclick="javascript:testEach();">TEST</button> </body> </html>$.each の中の this にはオブジェクト型で渡されるため、その中の値を取得するには this.valueOf とします。
この方法は面倒なので、一つ前の index, value を用いる方法が良いと思います。
最後に、繰返し処理のなかで for 文の break, continue の様な処理に付いて説明します。
以下の例では、6件の配列データを宣言し、2番目までは処理を continue し、5番目以降で break する処理を行います。
■配列に対する each 処理での break, continue 例
<html> <head> <meta charset="utf-8"> <title>test checkbox</title> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script type="text/javascript"> //TEST関数 function testEach() { // 6件の配列 var arr = ['A001', 'B002', 'C003', 'D004', 'E005', 'F006']; $.each(arr, function(index, value) { // indexは[0]から始まることに注意!! if (index <= 1) { // 2番目までは処理をcontinue return true; } if (index >= 4) { // 5番目以降でbreak return false; } console.log('index(' + index + ') = ' + value); }); } </script> </head> <body> <h2>test each 6</h2> <button onclick="javascript:testEach();">TEST</button> </body> </html>
コンソールの出力は以下の様になります。index(2) = C003 index(3) = D004
関連する記事
⇒JavaScript 何に使う
⇒JavaScript jQueryの使い方(セレクタ)
⇒JavaScript jQueryの使い方(セレクタ)その2
⇒JavaScript 関数の宣言について(function)
⇒JavaScript jQueryでJavascriptファイルの動的に変更する方法
-
今回はPHPで使われる日付ライブラリの Carbon の使い方について説明したいと思います。
なお Carbon のインストールについては以下の記事を参照して下さい。
⇒PHP Carbon(ライブラリ)を使って日付処理・インストール
以下の順で説明したいと思います。■Carbon インスタンスの生成
先ずは Carbon クラスのインスタンスの生成について例をあげて説明します。
普通に new Carbon() とすることで Carbon のインスタンスを生成できます。 生成されたインスタンスを指し示す変数から各種のメソッドを使うことで各種の処理ができます。
また Carbon 備わった各種のスタティックなメソッドでもインスタンスの生成ができます。 以下の例では now() yesterday() tomorrow() などを示しています。
new Carbon('日付指定文字列') のクラスの引数に日付指定文字列を渡すことで指定した日付のインスタンスを生成できます。<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // インスタンス生成:現在のシステム日時 $dtCar = new Carbon(); echo "現在のシステム日時: ".$dtCar."<br>\n"; // 文字列を返すデフォルトのメソッドは「__toString()」 echo "現在のシステム日時: ".$dtCar->__toString()."<br>\n"; // static な関数による生成 // インスタンス生成(static):本日 $dtNow = Carbon::now(); echo "static-本日: ".$dtNow."<br>\n"; // インスタンス生成(static):昨日 $dtYes = Carbon::yesterday(); echo "static-昨日: ".$dtYes."<br>\n"; // インスタンス生成(static):明日 $dtTom = Carbon::tomorrow(); echo "static-明日: ".$dtTom."<br>\n"; // Carbonクラス生成時にパースを渡す // クラス生成時に日付文字列を渡す $dt1 = new Carbon('2022-11-30'); echo "日付文字列を渡す: ".$dt1."<br>\n"; // クラス生成時に日付加算文字列を渡す(システム日付[2022-11-29]に対して次の日) $dt2 = new Carbon('+1 days'); echo "日付加算文字列を渡す: ".$dt2."<br>\n"; // クラス生成時に月数加算文字列を渡す(システム日付[2022-11-29]に対して2か月後) $dt3 = new Carbon('+2 months'); echo "月数加算文字列を渡す: ".$dt3."<br>\n"; // クラス生成時に年数加算文字列を渡す(システム日付[2022-11-29]に対して2年後) $dt4 = new Carbon('+2 years'); echo "年数加算文字列を渡す: ".$dt4."<br>\n"; // クラス生成時に日指定文字列を渡す(システム日付[2022-11-29]に対して次月の初日) $dt5 = new Carbon('first day of next month'); echo "次月の最初の日: ".$dt5."<br>\n"; // クラス生成時に日指定文字列を渡す(システム日付[2022-11-29]に対して前月の初日) $dt6 = new Carbon('first day of last month'); echo "前月の最初の日: ".$dt6."<br>\n"; // クラス生成時に日指定文字列を渡す(システム日付[2022-11-29]に対して次月の末日) $dt7 = new Carbon('last day of next month'); echo "次月の最後の日: ".$dt7."<br>\n"; // クラス生成時に日指定文字列を渡す(システム日付[2022-11-29]に対して前月の末日) $dt8 = new Carbon('last day of last month'); echo "前月の最後の日: ".$dt8."<br>\n"; // クラス生成時に日付指定の生成メソッドを使用 $dt9 = Carbon::createFromDate(2022, 9, 25); echo "日付指定の生成メソッド: ".$dt9."<br>\n"; // クラス生成時に日時指定の生成メソッドを使用 $dt10 = Carbon::create(2022, 9, 25, 17, 10, 36, 'Asia/Tokyo'); // タイムゾーン指定は無くてもOK echo "日時指定の生成メソッド: ".$dt10."<br>\n"; ?>このプログラムの実行結果は以下の通りです。
現在のシステム日時: 2022-11-29 08:48:39 現在のシステム日時: 2022-11-29 08:48:39 static-本日: 2022-11-29 08:48:39 static-昨日: 2022-11-28 00:00:00 static-明日: 2022-11-30 00:00:00 日付文字列を渡す: 2022-11-30 00:00:00 日付加算文字列を渡す: 2022-11-30 08:48:39 月数加算文字列を渡す: 2023-01-29 08:48:39 年数加算文字列を渡す: 2024-11-29 08:48:39 次月の最初の日: 2022-12-01 08:48:39 前月の最初の日: 2022-10-01 08:48:39 次月の最後の日: 2022-12-31 08:48:39 前月の最後の日: 2022-10-31 08:48:39 日付指定の生成メソッド: 2022-09-25 08:48:39 日付指定の生成メソッド: 2022-09-25 17:10:36
■日付データの取得(Getter)
Carbon クラスのインスタンスの生成しその日付データから各種の日付に関するデータを取得できます。
日付データのなかで良く使われるであろうものをピックアップしました。
取得の名前をみると VB.NET の DateTime 型のプロパティとよく似ていると思いますが、真似をしたのでしょうか?
とにかく、実際に例を以下に示します。<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // クラス生成時に日付文字列を渡す $dt = new Carbon('2022-11-30 12:25:30.123456'); echo "<pre>"; echo "日付:".$dt->format('Y/m/d H:i:s.u')."\n"; // 各種 getter(戻り値はInteger) // 年 echo '$dt->year :';var_dump($dt->year); // 月 echo '$dt->month :';var_dump($dt->month); // 日 echo '$dt->day :';var_dump($dt->day); // 時 echo '$dt->hour :';var_dump($dt->hour); // 分 echo '$dt->minute :';var_dump($dt->minute); // 秒 echo '$dt->second :';var_dump($dt->second); // マイクロ秒 echo '$dt->micro :';var_dump($dt->micro); // 週のIndex値 (日:0, 月:1, 火:2, 水:3, 木:4, 金:5, 土:6) echo '$dt->dayOfWeek :';var_dump($dt->dayOfWeek); // 年の何日目(0から始まる) echo '$dt->dayOfYear :';var_dump($dt->dayOfYear); // 月の何週目(1から始まる) echo '$dt->weekOfMonth:';var_dump($dt->weekOfMonth); // 年の何週目(1から始まる) echo '$dt->weekOfYear :';var_dump($dt->weekOfYear); // 月の日数 echo '$dt->daysInMonth:';var_dump($dt->daysInMonth); // 第何四半期か echo '$dt->quarter :';var_dump($dt->quarter); echo "</pre>"; ?>このプログラムの実行結果は以下の通りです。これらの値は全て Integer 型で返されます。
日付:2022/11/30 12:25:30.123456 $dt->year :int(2022) $dt->month :int(11) $dt->day :int(30) $dt->hour :int(12) $dt->minute :int(25) $dt->second :int(30) $dt->micro :int(123456) $dt->dayOfWeek :int(3) $dt->dayOfYear :int(334) $dt->weekOfMonth:int(5) $dt->weekOfYear :int(48) $dt->daysInMonth:int(30) $dt->quarter :int(4)
■日付データの設定(Setter)
上記の「日付データの取得(Getter)」では各種の日付データの取得を行いましたが、 ここではその Getter の名前に値を設定することで日付データインスタンス内の値を変更することが出来ます。
<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // 取敢えずクラス生成 $dt = new Carbon(); // 各種 setter // 年 $dt->year = 2022; // 月 $dt->month = 12; // 日 $dt->day = 1; // 時 $dt->hour = 13; // 分 $dt->minute = 45; // 秒 $dt->second = 29; // マイクロ秒 $dt->micro = 987654; // 日付表示 echo "日付:".$dt->format('Y/m/d H:i:s.u')."\n"; ?>このプログラムの実行結果は以下の通りです。
日付:2022/12/01 13:45:29.987654
■日付データの加減算
上記の「日付データの取得(Getter)」の名前に「add」及び「sub」では各種の日付データの取得を行いましたが、 ここではその Getter の名前に値を設定することで日付データインスタンス内の値を変更することが出来ます。
以下に加減算を行うメソッドの主なものを示します。 取敢えず実行結果は長くなるので、コメントとして右側に表示しています。<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // クラス生成時に日付文字列を渡す $dt = new Carbon('2022-11-30 12:25:30.123456'); echo "<pre>"; echo "日付:".$dt->format('Y/m/d H:i:s.u')."\n"; // 各種 加減算 // 世紀 echo '世紀'."\n"; // 取敢えず結果をコメントで表示 echo $dt->addCenturies(4)."\n"; //指定世紀数分加算 // 2422-11-30 12:25:30 echo $dt->addCentury()."\n"; //1世紀加算 // 2522-11-30 12:25:30 echo $dt->subCentury()."\n"; //1世紀減算 // 2422-11-30 12:25:30 echo $dt->subCenturies(4)."\n"; //指定世紀数分減算 // 2022-11-30 12:25:30 // 年 echo '年'."\n"; echo $dt->addYears(2)."\n"; //指定年数分加算 // 2024-11-30 12:25:30 echo $dt->addYear()."\n"; //1年加算 // 2025-11-30 12:25:30 echo $dt->subYear()."\n"; //1年減算 // 2024-11-30 12:25:30 echo $dt->subYears(2)."\n"; //指定年数分減算 // 2022-11-30 12:25:30 // 月 echo '月'."\n"; echo $dt->addMonths(60)."\n"; //指定月数分加算 // 2027-11-30 12:25:30 echo $dt->addMonth()."\n"; //1月加算 // 2027-12-30 12:25:30 echo $dt->subMonth()."\n"; //1月減算 // 2027-11-30 12:25:30 echo $dt->subMonths(60)."\n"; //指定月数分減算 // 2022-11-30 12:25:30 // 日 echo '日'."\n"; echo $dt->addDays(29)."\n"; //指定日数分加算 // 2022-12-29 12:25:30 echo $dt->addDay()."\n"; //1日加算 // 2022-12-30 12:25:30 echo $dt->subDay()."\n"; //1日減算 // 2022-12-29 12:25:30 echo $dt->subDays(29)."\n"; //指定日数分減算 // 2022-11-30 12:25:30 // 週 echo '週'."\n"; echo $dt->addWeeks(3)."\n"; //指定週分加算 // 2022-12-21 12:25:30 echo $dt->addWeek()."\n"; //1週加算 // 2022-12-28 12:25:30 echo $dt->subWeek()."\n"; //1週減算 // 2022-12-21 12:25:30 echo $dt->subWeeks(3)."\n"; //指定週分減算 // 2022-11-30 12:25:30 // 週(土日以外) echo '週'."\n"; echo $dt->addWeekdays(4)."\n"; //指定週分加算 // 2022-12-06 12:25:30 echo $dt->addWeekday()."\n"; //1世紀加算 // 2022-12-07 12:25:30 echo $dt->subWeekday()."\n"; //1世紀減算 // 2022-12-06 12:25:30 echo $dt->subWeekdays(4)."\n"; //指定週分減算 // 2022-11-30 12:25:30 // 時 echo '時'."\n"; echo $dt->addHours(24)."\n"; //指定時間分加算 // 2022-12-01 12:25:30 echo $dt->addHour()."\n"; //1時間加算 // 2022-12-01 13:25:30 echo $dt->subHour()."\n"; //1時間減算 // 2022-12-01 12:25:30 echo $dt->subHours(24)."\n"; //指定時間分減算 // 2022-11-30 12:25:30 // 分 echo '分'."\n"; echo $dt->addMinutes(61)."\n"; //指定分数加算 // 2022-11-30 13:26:30 echo $dt->addMinute()."\n"; //1分加算 // 2022-11-30 13:27:30 echo $dt->subMinute()."\n"; //1分減算 // 2022-11-30 13:26:30 echo $dt->subMinutes(61)."\n"; //指定分数減算 // 2022-11-30 12:25:30 // 秒 echo '秒'."\n"; echo $dt->addSeconds(61)."\n"; //指定秒数加算 // 2022-11-30 12:26:31 echo $dt->addSecond()."\n"; //1秒加算 // 2022-11-30 12:26:32 echo $dt->subSecond()."\n"; //1秒減算 // 2022-11-30 12:26:31 echo $dt->subSeconds(61)."\n"; //指定秒数減算 // 2022-11-30 12:25:30 echo "</pre>"; ?>■日付データの比較
日付データの比較は「等しい」「大きい」「小さい」などの英語表記の以下のメソッドがあります。
- 等しい eq() equalTo() =
- 等しく無い ne() notEqualTo() !=
- 大きい gt() greaterThan() >
- 以上 gte() greaterThanOrEqualTo() >=
- 小さい lt() lessThan() <
- 以下 lte() lessThanOrEqualTo() <=
以下に比較を行うメソッドの主なものを示します。 取敢えず実行結果は長くなるので、コメントとして右側に表示しています。<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // クラス生成時に日付文字列を渡す // 日付の設定 $first = Carbon::create("2022-10-05"); $second = Carbon::create("2022-10-06"); echo "<pre>"; // $second から見て $first がどうかを比較 // equal var_dump($first->eq($second)); // bool(false) // not equal var_dump($first->ne($second)); // bool(true) // greater than var_dump($first->gt($second)); // bool(false) // greater than or equal var_dump($first->gte($second)); // bool(false) // less than var_dump($first->lt($second)); // bool(true) // less than or equal var_dump($first->lte($second)); // bool(true) echo "</pre>"; ?>■日付データのデータ変換
Carbon には日付データから Array、Object(stdclass)、DateTimeクラス、DateTimeImmutableクラスへの変換用メソッドがあります。 これらのメソッドが有用かどうかは別として、取り敢えず紹介しておきます。
<?php // ライブラリ読込 require $_SERVER['DOCUMENT_ROOT'].'vendor/autoload.php'; // ライブラリ使用宣言 use Carbon\Carbon; // クラス生成 $dt = Carbon::createFromFormat('Y-m-d H:i:s.u', '2022-12-05 16:45:27.612984'); echo "<pre>"; // Array への変換 $arrDt = $dt->toArray(); var_dump($arrDt); // Object への変換(stdclass) $objDt = $dt->toObject(); var_dump($objDt); // DateTime への変換 $dateDt = $dt->toDate(); // Same as $dt->toDateTime() var_dump($dateDt); // DateTimeImmutable への変換 $objDtim = $dt->toDateTimeImmutable(); var_dump($objDtim); echo "</pre>"; ?>このプログラムの実行結果は以下の通りです。
array(12) { ["year"]=> int(2022) ["month"]=> int(12) ["day"]=> int(5) ["dayOfWeek"]=> int(1) ["dayOfYear"]=> int(339) ["hour"]=> int(16) ["minute"]=> int(45) ["second"]=> int(27) ["micro"]=> int(612984) ["timestamp"]=> int(1670258727) ["formatted"]=> string(19) "2022-12-05 16:45:27" ["timezone"]=> object(Carbon\CarbonTimeZone)#4 (2) { ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } } object(stdClass)#3 (12) { ["year"]=> int(2022) ["month"]=> int(12) ["day"]=> int(5) ["dayOfWeek"]=> int(1) ["dayOfYear"]=> int(339) ["hour"]=> int(16) ["minute"]=> int(45) ["second"]=> int(27) ["micro"]=> int(612984) ["timestamp"]=> int(1670258727) ["formatted"]=> string(19) "2022-12-05 16:45:27" ["timezone"]=> object(Carbon\CarbonTimeZone)#5 (2) { ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } } object(DateTime)#6 (3) { ["date"]=> string(26) "2022-12-05 16:45:27.612984" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" } object(DateTimeImmutable)#8 (3) { ["date"]=> string(26) "2022-12-05 16:45:27.612984" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }
-
DateTime クラス(オブジェクト)は良く使うクラスですが、コピーについては注意が必要なことがあります。
以下のソースを見て下さい。単に「$datetime1」に日付を設定し「$datetime2」にコピーをしています。<?php $datetime1 = new DateTime('2022-11-20 10:30:00'); $datetime2 = $datetime1; $datetime2->modify('+1 day'); echo "\$datetime1 = ".$datetime1->format('Y-m-d')."<br>\n"; echo "\$datetime2 = ".$datetime2->format('Y-m-d')."<br>\n"; ?>
これを実行するとブラウザに以下の様に表示されます。$datetime1 = 2022-11-21 $datetime2 = 2022-11-21
「$datetime2」にコピーをしているので「$datetime1」に影響しないと思いきや、「$datetime2」に modify メソッドで日付を1日加算すると 「$datetime1」「$datetime2」共に同じ日付になります。
「$datetime2」へのコピーでは参照渡しの様な感じになる様です。(実際のPHPの中では参照では無い様ですが…)
そこで、これを解消するにはクローン命令で別のインスタンスを作成し「$datetime2」に代入する必要があります。<?php $datetime1 = new DateTime('2022-11-20 10:30:00'); $datetime2 = clone $datetime1; echo "\$datetime1 = ".$datetime1->format('Y-m-d')."<br>\n"; echo "\$datetime2 = ".$datetime2->format('Y-m-d')."<br>\n"; $datetime2->modify('+1 day'); echo "\$datetime2 = ".$datetime2->format('Y-m-d')."<br>\n"; ?>
これを実行するとブラウザに以下の様に表示されます。$datetime1 = 2022-11-20 $datetime2 = 2022-11-20 $datetime2 = 2022-11-21
modify や add メソッドの戻り値は自分自身の DateTime オブジェクトを返します。
実際 PHP の正規のマニアルには以下の様に記述されています。戻り値: メソッドチェインに使う、変更された DateTime オブジェクトを返します。
メソッドチェイン とは以下の様な使い方です。
<?php $datetime1 = new DateTime('2022-11-30 10:30:00'); echo "\$datetime1 = ".$datetime1->modify('+1 day')->format('Y-m-d')."<br>\n"; echo "\$datetime1 = ".$datetime1->modify('+1 day')->modify('+1 day')->format('Y-m-d')."<br>\n"; echo "\$datetime1 = ".$datetime1->format('Y-m-d')."
\n"; ?>3行目では modify メソッドの直後に format メソッドを呼出しています。modify は DateTime オブジェクトを返すので、この方法が可能です。 さらに、4行目では modify メソッドの直後に再度 modify メソッドを呼出しています。
実行結果は以下の様に表示されます。 5行目では再度「$datetime1」の値を表示していますが、3回の modify の実行で日付は初期値から3日後になります。 modify では自分のオブジェクトを変更することがわかります。$datetime1 = 2022-12-01 $datetime1 = 2022-12-03 $datetime1 = 2022-12-03
ところで DateTime の値を変更する modify メソッド等で新しい DateTime オブジェクトを返したい場合には DateTimeImmutable クラスを使用します。Immutable(イミュータブル) とは「不変」「変わらない」ことを意味するそうです。
では DateTimeImmutable クラスを使用して最初のソースを変更します。<?php $datetime1 = new DateTimeImmutable('2022-11-20 10:30:00'); $datetime2 = $datetime1->modify('+1 day');; echo "\$datetime1 = ".$datetime1->format('Y-m-d')."<br>\n"; echo "\$datetime2 = ".$datetime2->format('Y-m-d')."<br>\n"; ?>実行結果は以下の様に表示されます。 「$datetime1」の modify メソッドの結果は別のオブジェクトとして「$datetime2」に設定された様です。 ただし、「$datetime1」の値は変化がありません。
$datetime1 = 2022-11-20 $datetime2 = 2022-11-21
-
以下の記事では、クラス(オブジェクト)の反復処理について Iterator インターフェースを使うところまでは説明を行いました。
⇒PHP クラス(オブジェクト)の反復処理について
Iterator インターフェースでは5個のメソッドを宣言しなければならないので、そのあたりを簡単にできる方法を説明します。 比較の為に、前回のソースを以下に示します。<?php // Iterator インターフェースを利用した反復処理テストクラス class cEach implements Iterator { // 内部の配列とする private $list = ["list1", "list2", "list3", "list4", "list5"]; // 配列の位置 private $pos = 0; // コンストラクタ public function __construct() { $this->pos = 0; } // 巻き戻し(初期位置) public function rewind(): void { $this->pos = 0; } // 現在値 public function current() { return $this->list[$this->pos]; } // 現在キー public function key() { return $this->pos; } // 次の位置へ public function next(): void { ++$this->pos; } // 現在位置のデータ存在チェック public function valid(): bool { return isset($this->list[$this->pos]); } } // [cEach]クラスの生成 $insEach = new cEach(); // インスタンスから取得できる反復データ foreach($insEach as $key => $value) { echo "$key => $value<br>\n"; } ?>
上記のクラスを今回は IteratorAggregate インターフェイスを使ってクラス(オブジェクト)の反復処理を書き変えます。
IteratorAggregate インターフェイスの概要は以下の様です。 getIterator メソッドの宣言は必須となります。interface IteratorAggregate extends Traversable { /* メソッド */ public getIterator(): Traversable // 外部イテレータを取得する }
それでは、書き変えたソースを以下に示します。
getIterator メソッドの戻り値に ArrayIterator クラスの生成値を戻しています。
getIterator の戻り値は Traversable インターフェース型である必要がありますが、 ArrayIterator は配列型データを Traversable インターフェース型のクラスを生成しています。<?php // IteratorAggregate インターフェースを利用した反復処理テストクラス class cEach implements IteratorAggregate { // 内部の配列とする private $list; // コンストラクタ function __construct(array $_list) { // 外部からの配列を内部に退避(配列はシャローコピーではないので) $this->list = $_list; } // 外部イテレータを取得する public function getIterator() { return new ArrayIterator($this->list); } } // [cEach]クラスの生成 $arr = ["list1", "list2", "list3", "list4", "list5"]; $insEach = new cEach($arr); // インスタンスから取得できる反復データ foreach($insEach as $key => $value) { echo "$key => $value<br>\n"; } ?>
これを実行するとブラウザに以下の様に表示されます。0 => list1 1 => list2 2 => list3 3 => list4 4 => list5
上記の ArrayIterator を使っている部分を ジェネレータ と呼ばれる yield を使う方法でもできます。
以下に変更したソースを示します。<?php // IteratorAggregate インターフェースを利用した反復処理テストクラス class cEach implements IteratorAggregate { // 内部の配列とする private $list; // コンストラクタ function __construct(array $_list) { // 外部からの配列を内部に退避(配列はシャローコピーではないので) $this->list = $_list; } // ジェネレータ(yield)を使用する public function getIterator() { foreach ($this->list as $key => $val) { yield $key => $val; } } } // [cEach]クラスの生成 $arr = ["list1", "list2", "list3", "list4", "list5"]; $insEach = new cEach($arr); // インスタンスから取得できる反復データ foreach($insEach as $key => $value) { echo "$key => $value<br>\n"; } ?>
ジェネレータ と呼ばれる yield について少し説明します。
PHP の公式ドキュメントには以下の様に記述されています。ジェネレータ関数が呼ばれると、反復処理が可能なオブジェクトを返します。 このオブジェクトを (foreach ループなどで) 反復させると、値が必要になるたびに PHP がオブジェクトの反復メソッドを呼びます。 そして、ジェネレータが値を yield した時点の状態を保存しておき、 次に値が必要になったときにはそこから再開できるようにします。 yield できる値がなくなると、ジェネレータは単純に終了します。呼び出し元のコードでは、配列の要素をすべて処理し終えた後のように、そのまま処理が続きます。
ジェネレータ関数では yield は return 命令の様な感じで動きますが、 呼び出し元で繰り返し呼ばれることで、順次出力する内容が呼び出し元に返されます。
以下の例のジェネレータ関数は内部で宣言された配列を順次 yield で出力しています。 呼び出し元では foreach 命令の「$value」に値が返ってきます。<?php // ジェネレータ関数 function generator_func() { $arr = ["list1", "list2", "list3"]; foreach($arr as $val) { yield $val; } } // ジェネレータ関数の呼出 foreach (generator_func() as $value) { echo "$value<br>\n"; } ?>yield では {キー} => {値} の形での指定もできます。ソースを変更しました。
<?php // ジェネレータ関数 function generator_func() { $arr = ["list1", "list2", "list3"]; foreach($arr as $key => $val) { yield $key => $val; } } // ジェネレータ関数の呼出 foreach (generator_func() as $key => $value) { echo "$key => $value<br>\n"; } ?>