20210906のPHPに関する記事は8件です。

【Laravel】@sectionと@yieldの関係(初心者向け)

はじめに レイアウトを作成するにあたって必須の@sectionと@yieldについて簡単に説明します。 @sectionと@yieldの関係 @sectionの書き方には、 index.blade.php @section('セクション名', '画面に表示する値') と記述するパターンと、 index.blade.php @section(親テンプレートの@yield名) ~~~画面に表示する内容~~~ @endsection として、親(ベース)となるテンプレートに記述された@yield(名前)部分に、@sectionと@endsectionに囲まれた部分がはめ込まれるというパターンがあります。 具体例 layouts/app.blade.php(親となるテンプレート) <h1>@yield('title')</h1> <div class="container"> @yield('content') </div> menus/index.blade.php(子となるテンプレート) @section('title', '一覧画面') @section('content') <p>一覧画面を表示します</p> @endsection app.blade.phpの@yield('title')部分に、index.blade.phpの@section('title', '一覧画面')に記述した「一覧画面」が入り、同じくapp.blade.phpの@yield('content')部分に、index.blade.phpの@section('content')に記述した<p>一覧画面を表示します</p>がはめ込まれます。 おわりに 一度理解すれば簡単ですね。 ほかにも、@extendsや@includeもあるので、ググってみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP基礎】ページネーションの作り方

はじめに  PHPを使ったページネーションの実装方法について勉強しましたので、備忘録として残していきます。  ページを遷移させるだけですが、素のPHPで書こうと思うと結構ロジックを考えなければなりません。なるべく丁寧にまとめていきますのでよろしくお願いします。 ページネーションとは  ページネーションとは、ECサイトの商品件数や掲示板のコメントなど件数が多い場合に、一気に表示させるのではなく、ページ遷移を行うことで数件〜数十件ずつ取得していく手法のことです。普段何気無く使っている機能ですが、実装しようとすると結構ロジックを考えなければなりません。  何か機能を作る場合は、まず言語化することが大切です。今回の場合は下記のように言語化できるでしょう。ECサイトの商品件数を例としてあげていきます。 ①商品件数を1〜10件だけ取得する。 ②GET通信でページ数の値を与える ③リンクを作成する ④リンク先の値をチェック このような順序で進めていきます。 それでは実際にやっていきましょう。 商品件数を1〜10件だけ取得する  データベースから商品情報を取ってくる際は、SQLを使います。その際に、LIMIT句を使います。LIMIT 0,10とすることで商品情報の1〜10件目を取得することができます。10,10とすれば次の10件、20,10とすればさらにその次の10件が取得できます。なんだか出来そうな気がしてきましたね。ちなみに書き方は下記のようになります。 limit.sql SELECT * FROM items LIMIT 0,10; 注意点は、1件目から取得するのに1,10とするのではなく、0,10とすることです。コンピュータの世界は0から数えるのが基本ですので間違えないようにしましょう。 GET通信でページ数の値を与える  それでは次に、LIMIT句の開始点を動的に変化させていきます。そのためにはプレースホルダーを使っていきます。LIMIT ?,10として、?の部分に開始点を入れることで変化させていきます。この部分には、URLパラメータを使っていきます。GET通信の際に、URLの後ろに〜?page=1とすることで、スーパーグローバル変数\$_GET['page']に1という値が入ります。この調子で2,3,4と作っていきたいところですが、先ほど説明の通りLIMIT句の開始点には0,10,20という数字を入れていきたいです。次のように書いてみましょう。 page.php $page = $_GET['page']; $page = ($page - 1)*10  こうすることで、\$pageにはページが進むごとに0,10,20という数字が入っていきます。あとはこれをLIMIT句に当てはめていくだけですね。 リンクを作成する  さて、ここまでくればあとはリンクを貼っていくだけです。 HTMLのaタグを使用しましょう。1ページ目にはpage=1、2ページ目にはpage=2・・・あれ、どこまでリンクを作れば良いのでしょうか・・・?もう少し考える必要がありますね。ここでは繰り返し構文を使うのが便利です。(繰り返し構文の具体的な書き方はこちら)  しかし、繰り返し構文を使うには、何回繰り返せば良いのかという情報を取得する必要があります。今回の場合は、ページの上限数を取得してくる必要があります。まずはSELECT文で全ての件数を取得します。SELECT COUNT(*)とすることで、件数を取得することができます。 count.php try { $dbh = new PDO($dsn, $username, $password); $sql = 'SELECT COUNT(*) as cnt from items'; $stmt = $dbh->prepare($sql); $stmt->execute(); $rows = $stmt->fetch(); } catch (PDOException $e) { echo '接続できませんでした。理由:'.$e->getMessage(); }  そうして取得した件数を1ページに表示させたい件数で割ります。今回は10件表示させたいので10で割ります。こうすると、例えば全件数が20件の場合は2ページ、30件の場合は3ページといった具合にページ数が割り出せます。それでは、35件の場合はどうでしょうか。あれ、割り切れないですね。そんな時に便利な関数がceil関数です。小数点以下を繰り上げることができますので、35件の場合は4となります。 ceil.php $count = ceil($rows['cnt']/10);  このようにして全ページ数を取得できれば、あとはその数だけ繰り返しをするだけです。 リンク先の値をチェック  ここまでくれば一応ページネーション機能自体は完成です。しかしまだ問題が残っています。今回はURLパラメータを使ってページ遷移をしているので、URLに直接値を入力することができます。例えばページ上限の値より大きい値を入れられてしまった場合や、マイナスの数字を入れられてしまった場合は画面が真っ白になってしまいます。これを回避するために、値のチェックを入れることにします。 check.php if($page < 1){ $page=1; }elseif($page > $count){ $page=$count; }  このようにすることで、ページ数が1より少ない時は\$pageに1を、最大ページ数より多い時は\$countを代入してエラーを防ぎます。 まとめ  今回はページネーションの実装方法についてまとめていきました。結構大変だと思いますが、一つずつ丁寧に読み解いていくと問題なく実装できると思いますので挫けずに頑張りましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP タイプヒンティング(型宣言)を記載して引数、戻り値のデータ型を指定する

目的 タイプヒンティングを用いて引数と戻り値のデータ型を指定する方法をまとめる 情報 下記のサービスを用いて動作確認を行った。 https://paiza.io/ja 方法 下記のように記載することで引数の型を指定する事ができる。 function 関数名(型名 変数名) { 関数内部の処理 } 下記のように記載することで戻り値の型を指定する事ができる。 function 関数名(): 型名 { 関数内部の処理 } 利用できる型(PHPのバージョンにより異なる。下記はPHP7) 型名 概要 bool 真偽値 float 浮動小数点 int 整数 string 文字列 array 配列 callble コールバック関数 クラス名/インターフェイス名 self 現在のクラス 引数と戻り値の型を指定する例 数字を受け取って帰すだけの関数を定義する。 引数はint型を想定する。戻り値はint型を返すことを想定する。 function getNum(int $num): int { return $num; } echo getNum(1); // 1が出力される 引数はint型を想定して関数を定義しているが、文字列を与えてみる。 function getNum(int $num): int { return $num; } echo getNum('strです'); 下記のエラーが出力される。(関数の引数の型をint型で固定しているので文字列を渡すとエラーになる) PHP Fatal error: Uncaught TypeError: getNum(): Argument #1 ($num) must be of type int, string given, called in /workspace/Main.php on line 10 and defined in /workspace/Main.php:5 次に定義した関数の中で文字列を返してみる。 function getNum(int $num): int { return 'strです'; } echo getNum(1); 下記のエラーが出力される。(関数の戻り値の型をint型で固定しているので文字列を返すようにするとエラーになる) まとめ ケース・バイ・ケースではあるが、タイプヒンティング(型宣言)は使ったほうが良いと思った。 己のソースの記載ミスを早期に発見できてバグを減らすことができると思った。 参考文献 独習PHP
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP8.1】静的変数を継承したときの挙動が変更になる

細かすぎて伝わらない変更点。 PHPには静的変数という機能があります。 class A{ public static int $hoge = 1; // 普通のクラス変数 public function foo(){ static $foo = 1; // ← これ return $foo++; } } $a = new A(); $a->foo(); // 1 $a->foo(); // 2 $a->foo(); // 3 関数・メソッド内でstaticを付けて変数定義すると、その変数値はプログラムが終了するまでずっと保持されます。 イメージとしては、関数ローカルのクラス変数みたいなかんじでしょうか。 そしてこの静的変数、クラス変数と並べてみると動作がほんのり微妙に異なっているんですよね。 class A { public static int $hoge = 1; public function foo() { static $foo = 1; return $foo++; } } class B extends A {} echo A::$hoge++; // 1 echo B::$hoge++; // 2 echo A::$hoge++; // 3 echo B::$hoge++; // 4 $a1 = new A(); $a2 = new A(); echo $a1->foo(); // 1 echo $a2->foo(); // 2 echo $a1->foo(); // 3 echo $a2->foo(); // 4 $a = new A(); $b = new B(); echo $a->foo(); // 5 ← $a1/$a2と同じ echo $b->foo(); // 1 ← Bだけ違う echo $a->foo(); // 6 echo $b->foo(); // 2 $b2 = new B(); echo $b2->foo(); // 3 ←B同士であれば同じ echo $b->foo(); // 4 クラス変数ではA::$hogeとB::$hogeが指している先は必ず同じです。 静的変数の場合、同じクラスであれば同じですが、異なるクラスであれば別の変数になる、というよくわからない状態になっています。 これはこれで使い慣れたら使い道がありそうですが、わかりにくいし事故の元なので修正しようというRFCが提出されました。 既に受理されており、PHP8.1から動作が変更になります。 PHP RFC: Static variables in inherited methods Introduction 現状、静的変数を使っているメソッドを継承すると、継承先では別の静的変数を使います。 このRFCでは、ひとつのメソッドにたいして静的変数はひとつだけにすることを提案します。 以下は、現在の静的変数の例です。 class A { public static function counter() { static $i = 0; return ++$i; } } class B extends A {} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(1) var_dump(B::counter()); // int(2) A::counter()を継承した場合、継承先のクラスBでの静的変数は異なる値が使用され、A::counter()とB::counter()は異なる静的変数を管理することになります。 このRFCでは、継承にかかわらず、ひとつの静的変数はひとつの値を使うことを提案します。 class A { public static function counter() { static $i = 0; return ++$i; } } class B extends A {} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(3) var_dump(B::counter()); // int(4) 静的変数に関するバグレポートを参照する限りでは、これが直感的に期待される動作のようです。 また、これはクラス変数の動作とも一致します。 class A { private static $i = 0; public static function counter() { return ++static::$i; } } class B extends A {} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(3) var_dump(B::counter()); // int(4) また、他の言語の動作とも一致します。 C++の例 #include <iostream> class A { public: static int counter() { static int i = 0; return ++i; } }; class B : public A { }; int main() { std::cout << A::counter() << std::endl; // 1 std::cout << A::counter() << std::endl; // 2 std::cout << B::counter() << std::endl; // 3 std::cout << B::counter() << std::endl; // 4 return 0; } 現在の実装の問題点のひとつは、メソッドを子クラスでオーバーライドしてparent::を呼び出すと動作が変わるという点です。 class A { public static function counter() { static $i = 0; return ++$i; } } class B extends A { public static function counter() { return parent::counter(); } } var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(3) var_dump(B::counter()); // int(4) 一般的には、直接親メソッドを呼び出すのと、オーバーライドした子クラスからparent::を呼び出すのでは、プログラムの動作は変わらないはずです。 現在は、実装をまるごと子クラスにコピーしない限り、オーバーライドしつつ元の動作を再現する方法はありません。 最後に、静的変数には明らかなバグがあります。 コンストラクタ(および他のマジックメソッド)で静的変数を使った場合、それは同じ値になります。 class A { public function __construct() { static $i = 0; var_dump(++$i); } } class B extends A {} new A; // int(1) new A; // int(2) new B; // int(3) new B; // int(4) このRFCが受理された場合、この動作は正しいものになります。 このRFCが却下された場合、この動作はバグなので修正されなければなりません。 Proposal 静的変数を使用しているメソッドを継承しても、静的変数の指す値はひとつになります。 class A { public static function counter() { static $i = 0; return ++$i; } } class B extends A {} var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(3) var_dump(B::counter()); // int(4) ただし、トレイトの静的変数は値を共用しません。 trait T { public static function counter() { static $i = 0; return ++$i; } } class A { use T; } class B { use T; } var_dump(A::counter()); // int(1) var_dump(A::counter()); // int(2) var_dump(B::counter()); // int(1) var_dump(B::counter()); // int(2) トレイトの一般的なセマンティクスは『コードのコピペ』であり、トレイトのコードは単にそれぞれのクラスにコピペされたものとして扱われます。 Backward Incompatible Changes メソッド内の静的変数の挙動が変わります。 現在の静的変数の挙動はドキュメント化されていませんが、私はこの挙動はバグであると考えています。 静的変数の一般的な利用法であるメモ化については、よほど特殊なことをしていないかぎり影響はありません。 現在の仕様を意図的に使っているコードは、static::classでインデックス化することで互換することができます。 class A { public function counter() { // 静的メソッドでも通常のメソッドでも動く static $counters = []; $counters[static::class] ??= 0; return ++$counters[static::class]; } } class B extends A { } var_dump((new A)->counter()); // int(1) var_dump((new A)->counter()); // int(2) var_dump((new B)->counter()); // int(1) var_dump((new B)->counter()); // int(2) このコードは仕様変更前後で同じ動作をします。 Vote 投票は2021/04/14から2021/04/28に行われ、賛成32反対0の全員賛成で受理されました。 感想 わかりにくい! まあ、普通は静的変数自体をあんまり使わないですよね。 素直にクラス変数・インスタンス変数を使えって話ですよ。 いや、これこれこういう理由があって私は静的変数をばりばり使ってるんだ、という使い道があったら教えてください。 あと、RFCの例は親子関係だけだからわかりやすかったけど、複数の継承があった場合に「なんかわからんけど値がおかしくなった!」ってなるかもしれません。 class A { public function foo() { static $foo = 1; return $foo++; } } class B extends A{} class C extends A{} $b = new B(); $c = new C(); echo $b->foo(), $c->foo(), $b->foo(), $c->foo(); // PHP8.0まで1122、PHP8.1から1234 こんな使い方する方が悪いと言われればそのとおりですが。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Target class [〇〇〇TableSeeder] does not exist. って出てきたときにやったこと。

事象 Seederファイルに目的のデータを追加して、 DatabaseSeeder.phpにも追加。 php artisan migrate:refresh --seed を実行。 Illuminate\Contracts\Container\BindingResolutionException : Target class [XxxxxTableSeeder] does not exist. なぜかエラーに。 typoを疑い、探してみるも見つけられず。 原因 composerのリロードが必要だったようです。 composer dump-autoload # リロードした後に再作成。 php artisan migrate:refresh --seed 今度は問題なく再作成することができました。 〜〜 does not exist のようなエラーは、変にググるよりキャッシュを疑った方が効率的ですね! php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear composer dump-autoload
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】Bladeで共通で参照できるグローバルな変数を定義する。

自分用のメモとして残します。 各コントローラでわざわざviewに渡す変数を定義するのは面倒。 AppServiceProviderのbootメソッドで、全てのviewで参照できる変数をに定義する方法をメモ。 やり方 app\Providers\AppServiceProvider.php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Auth; class AppServiceProvider extends ServiceProvider { /** * Register any application services. * * @return void */ public function register() { } /** * Bootstrap any application services. * * @return void */ public function boot() { // view()->composer内でやっているのは、Authの情報を取るためなので、なくてもOK view()->composer('*', function ($view) { $globalArg_hoge = null; if (Auth::guard('user')->check()) { $globalArg_hoge = 'HOGE'; } // ポイント:view()->shareで変数を定義してあげることで、冗長にならなくなる。 view()->share([ 'globalArg_hoge'=> $globalArg_hoge, ]); }); } } 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【令和も対応】PHPで和暦⇔西暦変換

西暦を和暦に変換する処理を書く機会があって、また必要になるかも。 と思い、汎用的に使い回せるよう、関数を作成してみました。 PHPで、西暦⇔和暦変換をする機会のある方は、参考にしてください。 そんな難しくないです。 PHPで西暦 → 和暦 wareki.php // 西暦 => 和暦 function wareki($year) { $eras = array( array('year' => 2018, 'name' => '令和'), array('year' => 1988, 'name' => '平成'), array('year' => 1925, 'name' => '昭和'), array('year' => 1911, 'name' => '大正'), array('year' => 1867, 'name' => '明治') ); foreach($eras as $era) { $base_year = $era['year']; $era_name = $era['name']; if($year > $base_year) { $era_year = $year - $base_year; if($era_year === 1) { return $era_name .'元年'; } return $era_name . $era_year .'年'; } } return null; } echo wareki(2019); // 令和元年 PHPで和暦 → 西暦 seireki.php // 和暦 => 西暦 function seireki($wareki_year) { $wareki_year = str_replace('元年', '1年', mb_convert_kana($wareki_year, 'n')); if(preg_match('!^(明治|大正|昭和|平成|令和)([0-9]+)年$!', $wareki_year, $matches)) { $era_name = $matches[1]; $year = intval($matches[2]); if($era_name === '明治') { $year += 1867; } else if($era_name === '大正') { $year += 1911; } else if($era_name === '昭和') { $year += 1925; } else if($era_name === '平成') { $year += 1988; } else if($era_name === '令和') { $year += 2018; } return $year .'年'; } return null; } echo seireki('平成元年'); // 1989年 その他の記事 PHPで日、月、年の加算と減算方法 https://qiita.com/thiagomatsui/items/619775a96dce38bc5060 参考サイト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】余り計算の活用方法

<?php $cnt = 3; 3 % 3 余りは0 2 % 3 余りは2 1 % 3 余りは1 0 % 3 余りは0 $nocori = $cnt - (1 % 3); //残りは2となる ?> 4 % 4 余りは0 3 % 4 余りは3 2 % 4 余りは2 1 % 4 余りは1 0 % 4 余りは0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む