- 投稿日:2020-01-07T22:04:29+09:00
perlなどのsprintf()で整数のゼロ埋めと少数の有効数字の設定を同時にしたい
実現したいこと
3.5を003.500のように設定したい
# 答え my $text = sprintf("%07.3f", 3.5); # -> 003.500となる1. 整数のゼロ埋め
例)3を003のようにゼロ埋めしたい
my $text = sprintf("%03d", 3);2. 少数の有効数字の設定
例)3.5を3.500のようにしたい
my $text = sprintf("%.3f", 3.5);3. 1と2を組み合わせたい
例)3.5を003.500のように表現したい
以下のように1と2の書式を単純に組み合わせた場合、意図した形式にならない。# 意図した形式にならない例 my $text = sprintf("%03.3f\n", 3.5); # -> 3.500となる以下のように設定することで意図した形式になる。
# 意図した形式になる例 my $text = sprintf("%07.3f", 3.5); # -> 003.500となる少数以下の桁数 + コンマの数(1個)+ ゼロ埋め対象の桁数を
%と.の間に記入する。
例では、3+1+3=7なので07と記入する。
参考
- 投稿日:2020-01-07T21:52:01+09:00
【未経験エンジニア2日目(復習①)】URLの.htmlの削除
- 投稿日:2020-01-07T17:57:09+09:00
PHP 関数の作り方
目的
- PHPでの関数の作り方をまとめる
書き方の例
- 下記に関数の定義方法を記載する。
//関数の定義(引数の有無に関わらず括弧をつけて変数を定義する) function 関数名(第一引数を格納する変数A, 第二引数を格納する変数B){ 関数内で実行する処理; } //関数の呼び出し(定義時に引数が格納される変数の定義の有無に関わらず括弧をつけて呼び出す) 関数名(第一引数, 第二引数);
- 関数内での結果を変数に格納したい
//関数の定義 function 関数名(第一引数を格納する変数A, 第二引数を格納する変数B){ return 任意の処理; } $foo = 関数名(第一引数, 第二引数);
- 投稿日:2020-01-07T17:56:14+09:00
Laravel 日付関連の処理を施す
Carbonはphpに標準で存在するDateTimeクラスを拡張して、日付操作をより簡単にしてくれます。まず、composerにCarbonをインストールしましょう。
composer self-update //composer --versionでバージョンの確認ができます。そしたら、composerにCarbonをインストールしましょう。
composer require nesbot/carbon現在地点からの日時取得
hogehogeController.phpuse Carbon\Carbon; // 現在日時 $carbon_now = Carbon::now(); // 昨日 Carbon::yesterday(); // 今日 Carbon::today(); // 明日 Carbon::tomorrow(); // 2年進める $carbon_now->addYears(2); // 2年戻る $carbon_now->subYears(2); // 2ヶ月進む $carbon_now->addMonth(2); // 2日進む $carbon_now->addDays(2); // 2時間戻る $carbon_now->subHours(2); // 平日で2日進む $carbon_now->addWeekdays(2); // 2週間進む $carbon_now->addWeeks(2);こんな感じで簡単に色々できます。
参考にさせて頂いたサイト
https://leben.mobi/blog/php_date_carbon/php/
上記サイトにほとんど書いてあるので、参考にしてみましょう!
- 投稿日:2020-01-07T16:34:05+09:00
ちょっとお兄ちゃん?否定のフラグは絶対作らないでって言ったよね?
(CV: 渡部恵子)
普通のフラグ
<?php $is_a = true; if($is_a){ // Aだったら var_dump('Aでした'); } else { // Aじゃなかったら var_dump('Aではありませんでした'); }否定のフラグ
<?php $is_not_a = true; if($is_not_a){ // Aじゃなかったら var_dump('Aではありませんでした'); } else { // Aじゃない、じゃなかったら var_dump('Aじゃない、ではありませんでした'); // 脳内変換(あぁ、要するにAだったのね) }否定のフラグはfalseだった場合に「notのフラグのfalseだからつまりtrueってことか?」っていう脳内変換が必要になります
例だと「Aじゃない、じゃない」というフラグなので「こんなフラグ誰も作らないでしょ」と思うかもしれません
実際には「未入金かどうか」を「is_not_payment」とかやっちゃうパターンがあるあるです
こうしてしまうと「is_not_paymentがfalseだから未入金じゃない、つまり入金済みってことか」みたいな脳内変換が発生します
この場合は「入金済みかどうか」のフラグ「is_payment」みたいにしてあげると後々嬉しいことが多いですまとめ
否定のフラグを作ってしまいそうになったら肯定のフラグに作り直しましょう
- 投稿日:2020-01-07T16:32:31+09:00
Joker123およびS128の最新のオンラインゲームゲームをプレイする
簡単な勝利の闘鶏オンラインS128のヒントとコツ
闘鶏のゲームでは、1回のプレイでアリーナに2羽の鶏が集まります。 2羽の鶏が1つのアリーナに置かれたので、次に何が起こるか推測できます。
闘鶏(英語)で訳されている場合、鶏と戦う(雄鶏と戦う)または他の名前の鶏(闘鶏)または雄鶏と戦う(雄鶏と闘う/闘う/闘う)。英語の翻訳では、「Bangkok Chicken」という用語は使用していません。バンコクバンコクコックファイトという用語は、実際には、首都がバンコクであるタイの国から最初に来た鶏の種類のローカル指定です。バンコクの鶏は格闘闘争になるキャラクターと本能を持っています。
タイでは、鶏はタイまたはタイの鶏と名付けられ、他の種類の戦いの鶏も、ベトナムやビルマ/ビルマ(ミャンマー)の鶏など、最初に発見された国の名前に基づいて名付けられます。
簡単に勝利するためのヒントとコツ闘鶏をオンラインでプレイする
S128チキンオンラインでのコックファイトに勝つために、次のステップを検討してください。1.インストールする前に鶏肉の種類を慎重に選択してください
闘鶏ゲームのゲームで本当に必要なのは、闘鶏アリーナでヒーローとなる格闘鶏を選ぶ際の注意です。2.安全で信頼性の高い闘鶏エージェントサイトの選択
信頼できるサイトはデータのセキュリティも保証するため、オンラインギャンブルサイトの選択では、それは偶然ではなく、オンラインギャンブルのゲームのサイトの主力であるべきです。また、資金の支払いは迅速に処理され、すべてにエラーはありません払い戻し処理プロセス。 JENEBT.INFO は、入金、登録、出金などのすべてのプロセスにおける信頼できる高速の闘鶏エージェントの例であり、すでにアジアで記録を保持しています。3.闘鶏に十分な速さのインターネット接続を使用する
ライブ/ライブストリーミングで提供される闘鶏製品は、インターネット接続が常に安定しており、接続の切断を防止しないようにする必要があります。それが望ましくない場合は、闘鶏のゲームを見逃すことが確実です闘鶏試合で負ける可能性があります。S128 オンライン闘鶏のゲームでは、生きている闘鶏試合に勝つために必要であるため、プレイヤーには認識が本当に必要です。コックファイティングオンラインで簡単に勝つためのトリックの適用
4.プレイするとき感情になるのは簡単ではありません
あなたがコックファイトでプレーするとき、あなたは感情的に簡単にコントロールされている場合、試合を見る集中力が分かれているか焦点が合っていないので、少しの間夢中になってはいけません。ハードか何でも。5.プレイしたいときに予算を調整します
オンライン闘鶏のゲームでは、デポジットを行う前に最小ベット/ベットを確認する必要があり、ゲームに1から2ラウンド渡すだけで、必要なデポジット額に応じてベットを開始し、最小ベット/ベットに調整する必要がありますこれは、Joker123 などの各オンライン闘鶏エージェントによって調整されています。今回共有したコックファイティングの主力戦で勝つためのヒントと簡単なコツが、オンラインコックファイティングゲームであるWarm Regards Online Cockfighting Agent、JNEBET.INFO で勝つ方法を知る上での洞察に役立つことを願っています。
- 投稿日:2020-01-07T16:10:22+09:00
larave-adminでcheckboxをDBに保存
larave-adminはお手軽にさらっと管理画面を作れて便利です。
大まかな使用方法は他の記事にお任せするとしてcheckbox、multiselectなどをDBに保存するにはひと手間必要なので備忘録的メモです公式に記述があります。二つあるようですが今回はデータをカンマ区切りで登録する方法です。
https://laravel-admin.org/docs/#/en/model-form-fieldsclass Post extends Model public function getTagsAttribute($value) { return explode(',', $value); } public function setTagsAttribute($value) { $this->attributes['tags'] = implode(',', $value); } }そのまま引用しています。
get[elements]Attributeとset[elements]Attributeをoverwriteしています。マイグレーションはtextかvarcharあたりで
Schema::create('post', function (Blueprint $table) { $table->bigIncrements('id'); $table->text('tag'); $table->timestamps(); $table->softDeletes(); });これでDBにはカンマ区切りで保存されます
- 投稿日:2020-01-07T16:10:22+09:00
laravel-adminでcheckboxをDBに保存
larave-adminはお手軽にさらっと管理画面を作れて便利です。
大まかな使用方法は他の記事にお任せするとしてcheckbox、multiselectなどをDBに保存するにはひと手間必要なので備忘録的メモです公式に記述があります。二つあるようですが今回はデータをカンマ区切りで登録する方法です。
https://laravel-admin.org/docs/#/en/model-form-fieldsclass Post extends Model public function getTagsAttribute($value) { return explode(',', $value); } public function setTagsAttribute($value) { $this->attributes['tags'] = implode(',', $value); } }そのまま引用しています。
get[elements]Attributeとset[elements]Attributeをoverwriteしています。マイグレーションはtextかvarcharあたりで
Schema::create('post', function (Blueprint $table) { $table->bigIncrements('id'); $table->text('tag'); $table->timestamps(); $table->softDeletes(); });これでDBにはカンマ区切りで保存されます
- 投稿日:2020-01-07T15:23:22+09:00
Laravel 6-Passport APIの主キーとしてのUUID
Laravel 6 - UUID as Primary Key for Passport API
チュートリアルを続けたくない場合は、このチュートリアルと同じ機能を備えたhttps://github.com/JamesHemery/laravel-uuidをいつでも使用できます
If you don´t want to follow the tutorial, you can always use https://github.com/JamesHemery/laravel-uuid which has the same functionality as this tutorial
laravelをインストールする
Install laravel
ユーザーテーブルの移行の変更
modify users table migration
$table->uuid('id')->primary();パスポートをインストールする
Install Passport
移行を実行する
run migrations
composer laravel / dbalをインストールします
composer Install laravel/dbal
テーブルを変更する新しい移行を作成する
create a new migration to change table
Schema::table("oauth_access_token",function (Blueprint $table){ $table->string("user_id")->change(); });移行を再度実行します
run migrations again
ユーザーモデル内に、以下を追加します
Inside the User Model, add the following
use Illuminate\Support\Str; class User extends Authenticatable { use HasApiTokens, Notifiable; public $incrementing = false; //No more autoincrement field protected static function boot() { parent::boot(); // TODO: Change the autogenerated stub //Generate a new UUID when creating a new registry self::creating(function ($model){ $model->id = (string) Str::uuid(); }); } .... }この部分を他のモデルで再利用可能にしたい場合は、特性を作成できます
If you want to make this part reusable for other models, you can create a Trait
app \ Traits \ HasUuid.phpにファイルを作成しますcreate a file in
app\Traits\HasUuid.php<?php namespace App\Traits; use Illuminate\Support\Str; trait HasUuid{ public function getIncrementing() { return false; } protected static function boot() { parent::boot(); // TODO: Change the autogenerated stub self::creating(function ($model){ $model->id = (string) Str::uuid(); }); } }モデルでは、「HasApiToken」の横に新しい特性「HasUuid」を追加できます
In the model, next to
HasApiTokenyou can add the new traitHasUuidclass User extends Authenticatable { use HasApiTokens, Notifiable, SoftDeletes, HasUuid; ....残りは、APIの作成方法に関する以前のチュートリアルに従うことができます
The rest you can follow my previous tutorials on how to create an API
- 投稿日:2020-01-07T12:35:24+09:00
クラスとは
「クラス」とは
よくPHPの学習サイトではクラスは設計図に例えられます。
オブジェクト指向とは設計図(クラス)からインスタンス(オブジェクト)を作ることを言います。
このことからわかるようにオブジェクト指向では 「クラス」 というものが基本になります。クラスは class を使用して、以下の書式で作成します。
class クラス名 { 実装したい処理 }クラスが持つ変数をプロパティと呼びます。
クラスが持つ関数をメソッドと呼びます。class Math { //プロパティを定義 public $number1; public $number2; //メソッドを定義 function add() { return $this->number1 + $this->number2; } function minus() { return $this->number1 - $this->number2; } }プロパティは
public どこからでもアクセスできる
protected そのクラスと、サブクラスからしかアクセスできない
private そのクラスからしかアクセスできない
で定義します。× $this->$number1 〇 $this->number1クラスが持つ関数、いわゆるメソッドはfunction で定義します。
クラス内でプロパティやメソッドを参照するときは、$ this という変数を使います。
$ this はメソッドの定義の中でのみ使用できる、特殊な変数です。
このときプロパティ名に$(ダラー)はつけません。
- 投稿日:2020-01-07T11:34:53+09:00
php7.3からの新関数array_key_firstとarray_key_lastについて
配列の最初のキーを取得する際に
php7.3から*array_key_firstという関数が追加されました。<?php $array = ['a' => 1, 'b' => 2, 'c' => 3]; $firstKey = array_key_first($array); var_dump($firstKey); ?>-- 出力結果 string(1) "a"php7.2以前は配列の先頭要素を取り出そうとする際には
配列をreset()して…keys()で指定して取り出す…というようなことをしていましたが
この関数があれば配列の内部ポインタを変更する必要もなく一発で取得できるので便利ですね。参照
https://www.php.net/manual/ja/function.array-key-first.php
- 投稿日:2020-01-07T11:10:09+09:00
Laravelのバリデーションで、正規表現のパイプが使えない件
Laravelのバリデーションで、正規表現のパイプが使えない件
Laravelのバリデーション
Laravelには、いくつかのバリデーションルールが用意されており、パイプ区切りで実行したいルールをvalidateメソッドへ渡すことで、複数のルールを利用することができる。
[バリデーションルールの例]
ルール 説明 フィールドがメールアドレスとして正しいことをバリデートする ipv4 フィールドがIPv4アドレスの形式として正しいことをバリデートする required フィールドが入力データに存在しており、かつ空でないことをバリデートする regex フィールドが指定された正規表現にマッチすることをバリデートする sample.php// バリデーションの利用例(パイプ区切り) $validateRules = [ // 必須入力, 英数字のみ 'user_name'=>'required|regex:/^[0-9a-zA-Z]+$/', // 必須入力, メールアドレス形式 'mail'=>'required|email', ];正規表現のパイプが使えない
通常、正規表現ではパイプ(|)を用いて「OR条件」を利用することができるが、Laravelでは複数のルールを区切るためにパイプを使うため、上記の書き方では正規表現のパイプを利用することができない。
バリデーションルールをパイプ区切りではなく、配列で書くことで正規表現のパイプを利用できるようにする。sample.php// バリデーションの利用例(配列) $validateRules = [ // 必須入力, 「大阪」か「東京」のいずれかのみ 'location'=>['required','regex:/(大阪|東京)/'], ];
- 投稿日:2020-01-07T10:48:39+09:00
PHP foreach文まとめ
目的
- foreach文の書き方をまとめる
書き方の例
- foreach文は配列や連想配列に対し、先頭のデータを使用して順にループ処理を実行する。
- 下記にforeach文の書き方を記載する。(変数
cityには任意のデータが格納されているものとする。)foreach ($city as $キー名 => $キー名にリンクする配列に格納された値が格納される変数){ ループで実行される処理 }foreach ($city as $配列が順に格納される変数名){ ループで実行される処理 }具体的な書き方の例
- 連想配列
$scoresには任意のキーが設定されており、それぞれ任意の値が格納されているものとする。//連想配列定義 $scores = array("数学IA" => 70, "化学A" => 90, "世界史B" => 85 ) //ループ処理 foreach ($scores as $key => $value){ echo "{$key}は{$value}点です。"; } //出力結果 数学IAは70点です。化学Aは90点です。世界史Bは85点です。
- 投稿日:2020-01-07T10:30:38+09:00
今年できるようになったこと・来年の目標
はじめに
Qiitaに投稿をはじめてまだ間もないですが、せっかくの年末年始なので今年できるようになったことと来年の目標を書いていこうと思います。
簡単に自己紹介
とある会社でIT部門に配属され、2020年1月現在新卒2年目です。
大学までスポーツに明け暮れ、文系大学で心理学を専攻し、イギリス留学で英語に目覚め、なんだかんだあってプログラムを書いています。
プログラミング自体はもともと興味があり、初めてのHello world はプログラミングのオンラインスクールに通い始めた20歳の夏でした(照)
当時はhtml/css/JS/phpを基礎の基礎レベルで書いており、教材通りに書いただけで俺はなんでも作れるという謎の全能感に支配されていたのですが、入社してからボコボコにされて日々勉強に追われています。現在は社会人としてオンライン行動データのアクセスログ計測サービスの開発に携わっております。
今年できるようになったこと
自身が触ってみて身についたと感じるものをサービス/言語ごとに超簡単にまとめていきます。
真面目に書きます。AWS
AWSはかなり多くの種類のサービスを触りました。
業務でもメインで扱っているクラウドサービスで勉強の重要度もかなり高いです。【取得した資格】
・AWS Certified Cloud Practitioner(English)Cloud Front
・CloudFrontの基本的な仕組み
・EdgeLocation、キャッシングによるレイテンシーの低減
・Distributionの設定、ログとS3バケットとの連携
・Behaviourによるリクエストの振り分けCloud Watch
・CloudWatchの基本的な仕組み、メリット
・ダッシュボードの作成、参照、設定等
・アラームの設定
・アラームからスケーリングやSNSとの連携Route53
・AWSのDNSサービスとしてのRoute53
・各種レコードの概要
・AレコードにはELBも設定可能
・Route53で設定可能なルーティングポリシーと各種ポリシーのメリット/デメリット
・ブルーグリーンデプロイメントEC2
・インスタンスのセットアップ(AMI/インスタンスタイプ/VPC/サブネット/AvailavilityZone/セキュリティグループ)
ELB/ALB
・health checkによるインスタンスの健康管理
・リクエスト分配、ポート管理
・ターゲットグループの設定AutoScaling
・起動設定の各種設定項目の理解
・スケーリングポリシー(条件、台数、AMI、インスタンスキャパシティ)S3
・S3の仕組みの基本的な理解
・グローバルアクセスとリージョンの設定
・webサイトホスティングによる静的コンテンツへのリクエスト・レスポンス
・AWS CLIからの基本的操作(コピー、削除、アップロード、ダウンロード)
・ファイルのバージョン管理(バージョニング)
・IPアドレス、IAMによるアクセス制限
・バケットイベント(putイベントのみ)
・料金管理/最適化Athena
・基本的なクエリ操作(select, create table, CTAS, insert, drop table, alter table)
・パーティションの設定
・AWS CLIからの操作
・料金管理RDS
・RDSのメリット(スケーリングやセットアップの手軽さ、他AWSサービスとの連携)
・基本的なクエリ操作
・インスタンスサイズ(まだちょっと怪しい)
・VPC/サブネット/AZSystems Manager
・対象インスタンスの選択からコマンドの実行
・コマンドが途中でエラーになってもSUCCESSで終了することがある(なんとかしてくれ)ECS
・タスク定義の各種設定
・ECRのリポジトリ指定
・クラスターの設定/サービスの管理/タスクのモニタリング
・ドレイニングECR
・基本的なリポジトリ操作
・imageタグの作成プッシュまでCode Commit
・code commitでの基本的なバージョン管理の仕組み理解
・基本操作(add/commit/push)Secrets Manager
・Secrets Managerを使用するメリット
・キーの設定方法
・APIによるキーやキー情報の取得※別記事を書いてます!
AWS Secrets Managerを使おう!Trusted Advisor
・料金や仕様状況ダッシュボードの見方
Jenkins
・CIツールとは Jenkinsのメリットとは
・Jenkinsの基本的な仕組みの理解
・JenkinsCLIからの操作(job一覧取得/job作成/ビルド/jobの削除)
・Jenkinsのディレクトリ構成、jobの設定ファイル等の操作
・crontab(jobの定期実行周りで覚えたのでここに書きます。)※別記事を書いてます!
JenkinsJobの情報を取得する扱っている言語
php
自分が一番メインで書いている言語になります。
バージョンが5.6だなんて言えない・・・・基本的処理
・フレームワーク Laravel/CakePHP(EOL来てますが・・・)の基本文法理解
・DB操作(MySQL)
・s3、Athena操作shell script
最近はphpより書いている気がします。
最初は大嫌いでしたが半年くらい付き合っていたら好きになっちゃいました。・基本的処理
・DB処理(MySQL)
・Linuxコマンド各種python
ほとんど触ってないですしフレームワークもよくわかりません。
でも一応触ったので。。。その他
・ApacheJmeter
・OWASP ZAP
・cookieのsamesite属性周り
・ITP周りの規制関連の話
などなど・・・来年の目標
僕は正直売り上げを生むサービスを作るよりも考える方に快感を覚える性格なので、エンジニアリングのスキルは勿論のばしつつ、上流工程や企画にも積極的に参加していけたらと考えております。
ここでは一旦技術面の目標のみ書いておきます。資格
・AWS Certified Solutions Architect Associate
AWSの知識は本当に持っていて損はないどころか、もっと知識を付けないと会社で運営しているサービスにも追い付けないのでこれは必須にします。英語でとります。・AWS Certified SysOps Administrator Associate
上流工程に関わっていくにはベストプラクティスの提示や料金の最適化も検討できるようになる必要があるのでこの資格も狙っていきたいです。英語です。Seleniumを覚える!
業務ではブラウザ操作を行うテストが多く、単純な操作も多いので是非自動化したいと考えています。
まだ全く触っていないので具体的に何ができるかなど詳細は分かっていませんが、絶対キャッチしておきたいと思っています。Tableauを覚える!
業務等で使用する機会は今のところありませんが、BIツールについてしっかり知っておきたいので空き時間に触っていこうと思います。
まとめ
想像より時間がかかりましたが、自分の知識がどれほど身についているか、どこがまだわからないのかなどがはっきりするため、知識の棚卸は大切だと感じました。
今年中にしっかりと上記の目標を達成できるように空き時間を有効に使っていこうと思います!
- 投稿日:2020-01-07T10:12:11+09:00
Magentoで商品ページURLに絶対にカテゴリパスを付けない方法
Magento2系で開発をしていると、商品ページへの導線を設置しないといけないことがあります。
ところが、正直に商品データを取ってきてURLを取得すると、商品が所属するカテゴリのパスがURLについたりつかなかったりすることがあり、キレイに1つに定まらないことがあります。
もちろんMagentoではCanonical URLの設定を有効にしておくことで重複URLをGoogleから指摘されることはなくなるが、URLがブレるのはなんだかとても釈然としない思いをします。
(これはたとえ設定で商品URLにカテゴリパスを付けない設定にしていても起きます)普通に書くとどうなるか
何も考えずに商品データからURLを取得すると、以下のようになることが多いでしょう。
($this->productRepositoryは\Magento\Catalog\Api\ProductRepositoryInterfaceを利用するクラスにDIしている前提)$product = $this->productRepository->get($sku); $url = $product->getProductUrl();この書き方をすると、状況によってはURLが以下のようにいくつかのバリエーションを持ってしまいます。
- http://ドメイン名/foo.html
- http://ドメイン名/bar/foo.html
なぜ複数のパターンがあり得るか
\Magento\Catalog\Model\ProductのgetProductUrl()の実装を見ていくと、以下の順に処理をしていることがわかります。
- \Magento\Catalog\Model\Product\Url::getProductUrl()
- \Magento\Catalog\Model\Product\getCategoryId()
この\Magento\Catalog\Model\Product\getCategoryId()がクセモノで、定義をみると以下のように書かれています。
public function getCategoryId() { $category = $this->_registry->registry('current_category'); if ($category && in_array($category->getId(), $this->getCategoryIds())) { return $category->getId(); } return false; }この処理の中に出てくる、$this->_registryというのはMagento\Framework\Registryクラスのインスタンスです。
Magento内部でクラスをまたいだ変数の引き回しによく使われています。既にこのクラスにはdeprecatedがつけられていますが、未だにコア実装のあちこちで使われていて、このクラスを使わないと始末できないような処理もかなり存在します。
先の処理では他のクラスで登録されているかもしれないcurrent_categoryというキー値の値を取得し、値がセットされていて、かつ商品が属しているカテゴリIDにその値があるかをみています。さらに\Magento\Catalog\Model\Product\Url::getProductUrl()の処理を読みすすめると、以下のことがわかると思います。
- カテゴリIDがある場合はURL書き換えデータの検索にカテゴリIDを併用する
- カテゴリIDがない場合はURL書き換えデータの検索は商品IDだけになる
カテゴリパスを付けたくないときはどうするか
ここまで処理を読んできましたが、getProductUrl()には大事な箇所があります。それが以下の部分です。
if (!isset($params['_ignore_category']) && $product->getCategoryId() && !$product->getDoNotUseCategoryId()) { $categoryId = $product->getCategoryId(); }\Magento\Catalog\Model\Product\Url::getProductUrl()は定義上以下の2つの引数を取ります。
- \Magento\Catalog\Model\Product
- オプションパラメータ配列
$categoryIdに値がセットされるのを防ぐためには、\Magento\Catalog\Model\Product\Url::getProductUrl()の第2引数を
$params['_ignore_category'] = true;という構成にするか、\Magento\Catalog\Model\Product::getProductUrl()を呼び出す前に、
$product->setDoNotUseCategoryId(true);とすればOKです。
実際、関連商品やアップセル・クロスセル商品のリストを表示する処理ではsetDoNotUseCategoryId(true)が呼ばれています。まとめ
- Magentoで商品URLを取得する際は、たとえカテゴリパスをつけない設定にしていてもカテゴリパスがつくことがある。
- 商品URLにカテゴリパスをつけたくない場合は商品オブジェクトに対してsetDoNotUseCategoryId(true)を行う。
- または、URL生成処理に与えるパラメータに_ignore_categoryをtrueで含める。
というほんの僅かな対応で解決できます。
- 投稿日:2020-01-07T09:53:49+09:00
【 Laravel 】Laravel DB.comで『 CRUD簡単作成 』
Laravle DB.com を使って 「 ER図 → CRUD生成 」を試す!
以前にも書きましたが、Laravle DB.comでは「CRUD」のコードまで生成するようになりました。\(^o^)/
前提条件
- Laravelで環境を作ったことがある人(とりあえず動作するまで)
- Laravelの基本を理解している人(つもりの人)
- 確認環境:Laravel5.5/PHP7.2.1/MySQL5.6.38 (Chromeで確認)
メリット
- CRUDを自動生成!
- 超便利! ER図を保存できるので、1度作ったものを別のアプリにも転用しやすい!
- どのPCからでも同じデータを操作できる(ブラウザアプリだから)!
さあ、はじめて行きましょう!
【 LaravelDB.comへ ログイン 】
LaravelDB.com
Googleアカウントのみログイン可能です。
※現在はGoogleアカウントを持っていない人は少ないですからね〜
【 LaravelDB.comの POINT!! 】
ER図を作成していきますが重要事項があります!
<<重要>>
主キーのAutoIncrementは どのテーブルも『 id 』 と固定すること!!
LaravelのEloquentModel を便利に使うためには、どのテーブルも 『 id 』 と固定するのが吉です。
理由は「 モデル名::find($id); 」と便利に使う場合は 主キーのAutoIncrement 『 id 』 名にしておかないと動作しないからです( Laravelを勉強してる人はなんとなく知ってることでしょうか )。
※ laravelDB.comのCRUDでも生成されるファイルは「 ○○○::find($id); 」を使ってるためそ!
※ laravelに最初から入っているテーブル「user」「password_resets」は作成しないこと(migrate時に上書きしてしまいます)
※慣れれば簡単ですが、少しだけ慣れる時間は必要ですね。
【 CRUDを生成してみる! 】
まずは、ER図を簡単に作ってみましょう!!
その後に右メニュー「 ER図のLoad/Save 」をクリックすると以下画面が表示されます。
CRUDを生成するボタンが新しく出来ています!!!
※まだデバッグが全て終わってないため「BETA」と書いてますが、クリックです!!!
【 CRUD: 新しいプロジェクトを用意 】
【 CRUD: ダウンロードファイルを確認しましょう 】
Zip圧縮ファイルがダウンロードされるので、Zipを展開(解凍)して中を見てみましょう!
CRUDに必要なファイルが一式入っています。
ダウンロードしたファイル( 各フォルダ内のファイル )を移動しましょう!
※welcome.blade.phpはダウンロードしたファイルへのリンクが生成されているので、上書きしてください。
【 CRUD: 配置しおわったら「 Migrate 」しましょう 】
DBや.env設定など最低限の設定が終わっていたら
php artisan migrateで、テーブルを作成してください。
【 完成: ブラウザで確認しましょう! 】
http://localhost/ (URLは開発環境によって異なります) で確認しましょう!
画面の中央に今までなかったリンクが出来ています。あなたが作ったテーブルのCRUD画面へ遷移できますよ!!
画面が古いままの場合(Cacheかも)
以下コマンドでCacheをクリアしてみましょう
php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear
動作した後はコードを見ると良いでしょう
- Routing
- Controller
- Views
- Model 後は、自分で変更をいれていくだけですね。
こちらのイベントで操作方法等の勘所など解説する予定!
【G'sCreativeCollection #3】GEEKs_Output_LT
Outline】
・日時:1月11日(土)17:00~19:30
・会場:ShibuyaQWS(渋谷スクランブルスクエア15F)内
・参加費:無料
・定員:30名
日本から海外へ向けたアウトプット
laravelDB.com は日本人が作り、海外でも使われるプロダクトになることを願っております。
Twitterアカウント: LaravelDB.com
m(_ _)m
- 投稿日:2020-01-07T09:53:49+09:00
【 Laravel 】Laravel DB.comで『 CRUD簡単作成 』を解説
Laravle DB.com を使って 「 ER図 → CRUD生成 」を試す!
以前にも書きましたが、Laravle DB.comでは「CRUD」のコードまで生成するようになりました。\(^o^)/
私の開発環境
- Laravel5.5/PHP7.2.1/MySQL5.6.38 (Chromeで確認)
メリット
- CRUDを自動生成!
- 超便利! ER図を保存できるので、1度作ったものを別のアプリにも転用しやすい!
- どのPCからでも同じデータを操作できる(ブラウザアプリだから)!
さあ、はじめて行きましょう!
【 LaravelDB.comへ ログイン 】
LaravelDB.com
Googleアカウントのみログイン可能です。
※現在はGoogleアカウントを持っていない人は少ないですからね〜
【 LaravelDB.comの POINT!! 】
ER図を作成していきますが重要事項があります!
<<重要>>
主キーのAutoIncrementは どのテーブルも『 id 』 と固定すること!!
LaravelのEloquentModel を便利に使うためには、どのテーブルも 『 id 』 と固定するのが吉です。
理由は「 モデル名::find($id); 」と便利に使う場合は 主キーのAutoIncrement 『 id 』 名にしておかないと動作しないからです( Laravelを勉強してる人はなんとなく知ってることでしょうか )。
※ laravelDB.comのCRUDでも生成されるファイルは「 ○○○::find($id); 」を使ってるためそ!
※ laravelに最初から入っているテーブル「user」「password_resets」は作成しないこと(migrate時に上書きしてしまいます)
※慣れれば簡単ですが、少しだけ慣れる時間は必要ですね。
【 CRUDを生成してみる! 】
まずは、ER図を簡単に作ってみましょう!!
その後に右メニュー「 ER図のLoad/Save 」をクリックすると以下画面が表示されます。
CRUDを生成するボタンが新しく出来ています!!!
※まだデバッグが全て終わってないため「BETA」と書いてますが、クリックです!!!
【 CRUD: 新しいプロジェクトを用意 】
最低限Laravelがインストールした状態 を準備します!
この時点ではまだLOGINは作らないように!
【 CRUD: ダウンロードファイルを確認しましょう 】
Zip圧縮ファイルがダウンロードされるので、Zipを展開(解凍)して中を見てみましょう!
CRUDに必要なファイルが一式入っています。
ダウンロードしたファイル( 各フォルダ内のファイル )を移動しましょう!
※welcome.blade.phpはダウンロードしたファイルへのリンクが生成されているので、上書きしてください。
【 CRUD: 配置しおわったら「 Migrate 」しましょう 】
DBや.env設定など最低限の設定が終わっていたら
php artisan migrateで、テーブルを作成してください。
【 完成: ブラウザで確認しましょう! 】
http://localhost/ (URLは開発環境によって異なります) で確認しましょう!
画面の中央に今までなかったリンクが出来ています。あなたが作ったテーブルのCRUD画面へ遷移できますよ!!作成されたindex/show/editの画面
基本的な処理が最初から出来てます!捗りそうですね!
画面が古いままの場合(Cacheかも)
以下コマンドでCacheをクリアしてみましょう
php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear
動作した後はコードを見ると良いでしょう
- Routing
- Controller
- Views
- Model 後は、自分で変更をいれていくだけですね。
こちらのイベントで操作方法等の勘所など解説する予定!
【G'sCreativeCollection #3】GEEKs_Output_LT
Outline】
・日時:1月11日(土)17:00~19:30
・会場:ShibuyaQWS(渋谷スクランブルスクエア15F)内
・参加費:無料
・定員:30名
日本から海外へ向けたアウトプット
laravelDB.com は日本人が作り、海外でも使われるプロダクトになることを願っております。
Twitterアカウント: LaravelDB.com
m(_ _)m
- 投稿日:2020-01-07T01:52:31+09:00
PHPの言語仕様の理解を深める特殊な立ち回り
こんにちは!
先日の年始に、
FFmpegを使ってルパン三世タイトルジェネレーターをPHPで書いてみた
を書いたばかりですが、今日はPHPの言語仕様を追った特殊な立ち回りについてお話します!
この記事で扱う使用例はあくまで言語仕様の理解を深めるためのサンプルコードとして記述しています。環境
動作確認済環境
- macOS Catalina :
10.15.2- PHP :
7.3.1言語仕様の理解を深める
目次一覧
String型の文字列からfor文で1文字ずつ取得する
前提知識
PHP公式マニュアルの文字列(string型)のページ冒頭には、
stringは、文字が連結されたものです。とあります。
そして、stringは
PHPでは、文字は1バイトと同じです。とあります。
これにより、PHP上での文字列はマルチバイト文字が混合していたとしても、
- 文字を1バイトずつ連結
されたものになります。
上記で把握出来る通り、実はPHPでは下記のような立ち回りが可能です。
$str = "abcdefghi"; for($i = 0;$i < strlen($str);$i++) { echo $str[$i]."\n"; }出力結果は、
a b c d e f g h iとなります。
しかし、文字列は1バイト単位の文字で連結されているためマルチバイト文字が混合している場合は、上記コードで一文字ずつ取得は不可能です。
例えば、3バイト文字のUTF-8の場合に対象文字列が、
こんにちはである場合は、UTF8 文字コード表 3byte (e3)にあるように、
こ => e38193 ん => e38293 に => e381ab ち => e381a1 は => e381afとなります。
これはPHP上で、下記のようにバイナリデータを16進表現にコンバートを行えば確認出来ます。echo bin2hex("こ")."\n"; echo bin2hex("ん")."\n"; echo bin2hex("に")."\n"; echo bin2hex("ち")."\n"; echo bin2hex("は")."\n";そして、先程のfor文を用いて確認すると、
$str = "こんにちは"; for($i = 0;$i < strlen($str);$i++){ echo bin2hex($str[$i])."\n"; }出力結果は、
e3 81 93 e3 82 93 e3 81 ab e3 81 a1 e3 81 afとなり1バイトずつの文字が連結された文字列だと確認できます。
要するに、文字列が
- 3バイト文字のUTF-8のみ
である場合、3バイトずつの取得を行えば本来取得したい文字が期待できるわけです。
$str = "こんにちは"; for($i = 0;$i < strlen($str);$i += 3) { $first_byte = $str[$i]; $second_byte = $str[($i + 1)]; $third_byte = $str[($i + 2)]; $char = $first_byte . $second_byte . $third_byte; echo $char."\n"; }↓以下出力結果↓
こ ん に ち はよって、各文字のバイト数は例の通り、
echo strlen("こ")."\n"; //3 echo strlen("a")."\n"; //1で確認できますね!
シングルバイト文字とマルチバイト文字(UTF-8)が混合する想定で、文字列から一文字ずつ取得する場合は配列に一旦格納したほうが利便性が高いです。
$str = "こんにちは!World."; $str_array = array_values( array_filter( preg_split("//u",$str), "strlen" ) ); print_r($str_array); // Array ( [0] => こ [1] => ん [2] => に [3] => ち [4] => は [5] => ! [6] => W [7] => o [8] => r [9] => l [10] => d [11] => . )前回の記事でも解説しましたが、まずはシングルバイト文字やマルチバイト文字の混合する文字列を、
preg_split("//u",$str)で配列にします。
preg_splitは、正規表現で文字列を分割する組み込み関数で、
- 第一引数に検索パターン文字列
- 第二引数に対象文字列
を指定します。
上記の検索パターンのうち、
//はデリミタです。
そして、uはパターン修飾子で、UTF-8として処理を行います。
要するに、検索パターンの
//uはシングルバイト文字やマルチバイト文字等関係なく、UTF-8の文字全てにマッチすることになります。
この処理において生成された配列には、空文字(0バイト)のValueも含むIndexが含まれるため、
array_filter( preg_split("//u",$str), "strlen" );array_filterで配列を走査しています。
array_filterは、
- 第一引数に対象配列
- 第二引数にコールバック関数
を指定して、コールバーク関数の返り値がtrueのValue(Key名固定)のみの配列を返却します。
Valueが0バイトのIndexを参照した場合、コールバック関数のstrlenはint型の0を返り値とします。
int型の0はPHPの型の比較表から、bool値として扱う場合falseと評価するので、結果よりこのarray_filterの処理は、空文字のIndexを除去した配列を返却します。最後に、上記よりKey名が歯抜け状態になった配列の添字をarray_valuesで整えています。
使用例
シングルバイトのみの文字列であれば、そのまま文字を1字ずつ取得可能です。
$str = "abcdefg"; echo $str[0]; //a echo $str[3]; //dシングルバイトとマルチバイトの文字を許容する場合は、
function multi_byte_string_to_array($str) { return array_values( array_filter( preg_split("//u",$str), "strlen" ) ); } $str = "こんにちは!World."; $str_array = multi_byte_string_to_array($str); echo $str_array[0]."\n"; //こ echo $str_array[7]."\n"; //oとし取得可能です。
条件式の評価
前提知識
条件式と言えば、PHPのif文を思い浮かべますが、
$number = 5; if($number === 5) { echo "数字は5です"; }単純な上記のコード例では、PHPの公式マニュアルにある通り
式が TRUE と評価された場合、PHPは文を実行します。FALSE と評価された場合は、これを無視します。という処理がif文に対して走っています。
ここで重要なのは、
式が$number === 5であることです。
当たり前のように感じますが、$number === 5はTRUEもしくはFALSEと評価されることです。
よって、$is_number_5 = $number === 5; var_dump($is_number_5); //bool(true)となり
$is_number_5には$number === 5がtrue評価されたbool値が格納されています。なので、
$number = 5; $is_number_5 = $number === 5; if($is_number_5) { echo "数字は5です"; }と同様です。
また論理演算子を用いて、
$number = 5; if($number !== 4 && $number !== 6) { echo "数字は4でも6でもありません"; }のように書くことがありますが、これも
$number = 5; $is_not_number_4_and_6 = $number !== 4 && $number !== 6; if($is_not_number_4_and_6) { echo "数字は4でも6でもありません"; }と同様です。
これは、条件式を評価するとbool値を取得できる簡単な例です。利用例
$number = 5; $is_not_number_4 = $number !== 4; $is_not_number_6 = $number !== 6; if($is_not_number_4 && $is_not_number_6) { echo "数字は4でも6でもありません"; }条件式が長くなってしまう際に、変数に予めbool値を格納して利用する場合があります。
他にも、
$number = 0; $bool = true; while($bool) { echo $number."\n"; $number++; $bool = $number < 5; }のように、while文の条件式の
$boolに予めtrueと格納しておきます。
そして、走査のたびに$numberが5より小さいかを評価したbool値を条件式として扱う$boolに再代入します。$boolがfalseになるまで、すなわち$numberが5になるまでwhile文は走査されることになります。論理演算子の仕組み
ここでは論理演算子の
論理和と論理積についてお話します。前提知識
$number = 5; $number !== 5 || $number = 1; echo $number; //1上記のコードを実行すると、
$numberが1になっていますね!これは、論理和が
左式または右式のどちらかがtrueであればtrueと評価する仕様に基づいた書き方です。まず、
左式がtrueであれば論理和の評価としてtrueを与えられることが確定しますよね!
そして、少なくともPHPでは論理和の左式がtrueであれば右式を評価しないという仕様になっています。なので、
$number = 1が評価されるのは$number !== 5の評価がfalseの時のみです。$number = 5; if( !( $number !== 5 ) ) { $number = 1; } echo $number;と同様の処理ですね!
上記で述べたとおり左式がtrueであれば、
$number = 5; $number === 5 || $number = 1; echo $number; //5
$numberには1が再代入されません。
論理積に関しては、予想できる通りに左式がfalseであれば、論理式の評価がfalseと確定するため右式は評価されません。
左式がtrueであれば右式は評価されます。使用例
仮に、
. ├── core │ ├── core.php │ └── functions.php │ └── function │ └── utility.php └── config └── config.phpと言ったディレクトリ構造の
core.phpで
- core/functions.php
- core/function/utility.php
- config/config.php
の3ファイルをincludeする際に、
$include_files_array = [ "../config/config.php", "./functions.php", "function/utility.php" ]; function include_files($files) { is_array($files) || $files = [$files]; foreach($files as $path) { include_once(__DIR__."/".$path); } } include_files($include_files_array);のように利用します。
上記コード中の
include_files関数は引数として、includeを行うファイルのパス一覧の一次元配列もしくは文字列のみのパスを許容可能です。それは、
is_array($files) || $files = [$files];によって、
$filesが配列でなければ1次元配列として引数を再宣言するためです。
文字列であっても一次元配列にするため、その後のforeachで問題なく走査処理が可能です。また、
htmlspecialcharsを使って
- 渡された引数が文字列であれば、サニタイズされた文字列を返り値とする
- 渡された引数が一次元配列であれば、全てのValueをサニタイズした一次元配列を返り値とする
といった関数であれば、
function h($stringer){ if(is_array($stringer) || !$stringer = htmlspecialchars($stringer)) { foreach($stringer as $key => $string) { $stringer[$key] = htmlspecialchars($string); } } return $stringer; }こう書くことが可能です。
is_array($stringer) || !$stringer = htmlspecialchars($stringer)上記の条件式では、
$stringerが
- 配列であれば
true- 文字列であれば
falseと評価されます。
可変変数
前提知識
PHPには動的に変数の参照をできる可変関数というものがあります。
これは、
$orange_price = "300円"; $var = "orange_price"; echo $$var; //300円変数名(
orange_price)を文字列として定義した変数($var)から300円($orange_price)という文字列を参照できるものです。また、
echo $$var; //300円 echo ${$var}; //300円のようにも書けるため、配列を参照する際に少しリーダブルになります笑
$price_list = [ "orange" => "300円" ]; $var = "price_list"; // echo $$var["orange"]; //300円 echo ${$var}["orange"]; //300円
※クラス内のメンバ変数(プロパティ)にも扱えます使用例
例として、Bootstrap等でフロントエンドのフォームを作成する際に下記のViewを生成する必要があったとします。
<div class="form-group"> <label for="name-sei"> 名前(姓): </label> <input type="text" class="form-control" id="name-sei" value="<?php echo $sei; ?>" required> </div> <div class="form-group"> <label for="name-mei"> 名前(名): </label> <input type="text" class="form-control" id="name-mei" value="<?php echo $mei; ?>" required> </div>このViewの情報を格納した連想配列として、
$form_info = [ [ "id" => "name-sei", "slug" => "名前(姓):", "value" => "sei" ], [ "id" => "name-mei", "slug" => "名前(名):", "value" => "mei" ] ];があったとします。
この際に同様のViewを生成するために、
<?php foreach($form_info as $form): ?> <div class="form-group"> <label for="<?php echo $form["id"]; ?>"> <?php echo $form["slug"]; ?> </label> <input type="text" class="form-control" id="<?php echo $form["id"]; ?>" value="<?php echo ${$form["value"]}; ?>" required> </div> <?php endforeach; ?>と可変変数を利用して書くことが出来ます。
可変関数
前提知識
可変関数は動的に関数を呼び出せるものです。
例として、
$html = '<h1 class="page-title">ページタイトル</h1>'; $func = "h"; function h($str) { return htmlspecialchars($str); } echo $func($html);のように扱えます。
※クラス内のメソッドにも扱えます使用例
可変変数の使用例と同様に連想配列中に関数名を文字列として定義しておき、任意のタイミング(Controller等)で発火させる等です。可変クラス
前提知識
可変クラスはPHPの公式マニュアルとしてページの存在を確認できませんでしたが、例として
Sample_Classというクラスのインスタンスを生成できる状態で、$class_name = "Sample_Class"; $sample_class = new $class_name();とすれば、
$sample_class = new Sample_Class();と同様の処理が実現できて、動的にインスタンスを生成することが出来ます。
使用例
__Debugger__Database上記2つのクラスのインスタンスが生成出来る状態で、
class __Loader{ private $class_mapper = [ [ "slug" => "debug", "class_name" => "__Debugger" ], [ "slug" => "db", "class_name" => "__Database" ] ]; public function __construct() { $this->assign_class(); } protected function assign_class() { foreach($this->class_mapper as $class) { $this->{$class["slug"]} = new $class["class_name"](); } } }というクラスがあったとします。
そして、
__Debuggerクラスにはpublicなプロパティとして$mode = "Developer"__Databaseクラスにはデータベースに接続処理を行うconnectというメソッドが存在する前提として、
$loader = new __Loader(); echo $loader->debug->mode; //Developer $loader->db->connect(); //DBへの接続処理といった処理を行う際に扱います。
※可変プロパティも例として扱っていますフレームワークの開発等をする際は扱うと思います。
三項演算子
前提知識
三項演算子は、
$high = true; if($high) { echo "オレンジ1個の値段は400円です"; } else { echo "オレンジ1個の値段は100円です"; }等の処理を、
$orange_price = $high ? "400" : "100"; echo "オレンジ1個の値段は".$orange_price."円です";と書くことができます。
エルビス演算子・エラー制御演算子
エルビス演算子は、
$bool = true; var_dump( true ?: "falseの場合に評価される" ); //bool(true)のように、
a ?: bに従った構文で書きます。この時、
aがtrueであれば、aがエルビス演算子の評価aがfalseであれば、bがエルビス演算子の評価であります。
エラー制御演算子は、
@$name;未定義のプロパティ(エラー)にアクセスをすると、返り値が0となります。
使用例
エルビス演算子とエラー制御演算子を用いて、
echo @$_POST['name'] ?: "Qiita君"; //Qiita君
$_POST['name']にアクセスできない場合は、エラー制御演算子が0を返り値とし、これはbool型で扱うとfalseであるため、Qiita君がechoされます。無名関数
前提知識
無名関数はその名の通り、関数名を宣言しません。
使用例
よって、関数を定義する程でも無い時に扱い、array_filter等の引数として必要なコールバック関数で簡易処理として扱うことが多いです。
$sample_array = [ 200, 300, 50, 400, 500 ]; $result = array_filter( $sample_array, function($value) { return $value > 250; } ); print_r($result); //Array ( [1] => 300 [3] => 400 [4] => 500 )最後に
後半はかなり殴り書きになってしまいました!笑
ですが、アウトプットと同時に知識の理解確認とこれまで以上に言語仕様の深堀りに興味が湧きました!
こういった言語仕様の理解をもっと深めたい方は、code golfがとてもオススメです!
code golfというのは如何に少ないバイト数で実現したい処理のコードを書けるか競うようなものです。
ここまで深堀りすると、言語のバージョンによって立ち回りに互換性が無かったりするのですが、その言語仕様の先に見える特殊な立ち回りは病みつきになったりします笑※リーダブルなコードが求められる業務では
code golfしてはいけません私自身まだまだ未熟者でありますので、チョットデキル方々お手柔らかにお願いします笑
- 投稿日:2020-01-07T01:22:22+09:00
【デザインパターン】PHPでStrategyパターンの実装をしてみた
環境
- PHP 7.2.18
はじめに
今更ながら、デザインパターンを真面目に理解し始めようとしている2年目エンジニアであります。
まずは事始めに「Strategyパターン」から勉強していこうと思い、この記事を書きました。
普通はJavaで勉強すべきだと思うのですが、Java初心者すぎるので、一番触っているPHPで勉強しています。
ちなみに、会社のブログでも同じような記事を書いたので、ここに貼っておきます。
レガシーコードをぶっ壊す!〜基本のキ編〜Strategyパターンとは
Strategyとは、「戦略」や「作戦」という意味を持ちます。
この「戦略」や「作戦」毎にクラスを分割して、簡単にそれらを切り替えることができるのが特徴です。
共通のインターフェースを定義し、クラスを使う側(以下クライアント)はそれに伴った処理を実行するので、クライアントは具体的な実装に依存しなくなります。
strategyパターンのクラス図は以下のようなものです。
Strategyパターンは何がいいか
自分が一番Strategyパターンを使うことで受けたメリットは、if文やswitch文などの複雑な条件分岐をスマートにすることです。
普段であれば場合分けしなければならないところを、「戦略」をクラスに格納することによりコードが非常にシンプルになり可読性や拡張性が上がります。例題の概要
今回は、例として簡単なプログラムを作りました。
URLのクエリパラメーターから、果物の名前を取得して、その果物の情報を表示しています。
イメージ図とクラス図です。イメージ図
クラス図
ファイル構成
ソースコード
https://github.com/nooboolean/strategy_practice
実装
まずはインターフェースの定義
まずはじめに、果物のクラスがどんな実装をしているべきなのかを定義します。
今回は、「名前」「色」「好きか嫌いか」「人気順位」をブラウザに表示するので、それぞれの情報を取得するメソッドを定義します。こんな感じです。FruitInterface.php<?php namespace Interfaces; interface FruitInterface{ public function getName(); public function getColor(); public function getHasLike(); public function getOrderOfPopularity(); }この後は、このインターフェースに従って具体的な実装を持つクラス(果物クラス)を実装していきます。
次は具体的な実装を持つクラス(果物クラス)の用意
先ほど定義したインターフェースに従って、それぞれの果物クラスを実装していきます。
例として、OrangeクラスとAppleクラスを記載しておきます。Orange.php<?php namespace Fruits; require_once('./Interfaces/FruitInterface.php'); use Interfaces\FruitInterface; class Orange implements FruitInterface { public function getName(){ return 'みかん'; } public function getColor(){ return 'orange'; } public function getHasLike(){ return '好き'; } public function getOrderOfPopularity(){ return 1; } }Apple.php<?php namespace Fruits; require_once('./Interfaces/FruitInterface.php'); use Interfaces\FruitInterface; class Apple implements FruitInterface { public function getName(){ return 'リンゴ'; } public function getColor(){ return 'red'; } public function getHasLike(){ return '好き'; } public function getOrderOfPopularity(){ return 3; } }どちらも定義されたメソッドに従って、情報をただ返しています。
最後に、これらのクラスを同じように扱えるようにコンテキストクラスを用意します。最後にコンテキストクラスの用意
上記で用意した具体的な実装を持つクラス(果物クラス)を抽象的に扱うことができるように、コンテキストクラスを実装します。
Fruit.php<?php namespace Fruits; require_once('./Interfaces/FruitInterface.php'); use Interfaces\FruitInterface; class Fruit { private $fruit; public function __construct(FruitInterface $fruit) { $this->fruit = $fruit; } public function execute() { $params = []; $params['name'] = $this->fruit->getName(); $params['color'] = $this->fruit->getColor(); $params['has_like'] = $this->fruit->getHasLike(); $params['order_of_popularity'] = $this->fruit->getOrderOfPopularity(); return $params; } }コンストラクタに渡ってくるインスタンスを、FruitInterfaceの型で縛り、渡ってくるインスタンスがFruitInterfaceをimplementsしていることを保証します。
実際に上記クラスを使ってブラウザに表示する部分の処理
これで、インターフェースとそれを実装する具象クラス、具象クラスを抽象的に扱うコンテキストクラスが用意されました。
これらを最後駆使して、ブラウザに情報を表示していきます。
まずはコード全体index.php<?php require_once('./Fruits/Fruit.php'); require_once('./Fruits/Orange.php'); require_once('./Fruits/Apple.php'); require_once('./Fruits/Grape.php'); require_once('./Fruits/NoneFruit.php'); use Fruits\Fruit; use Fruits\Orange; use Fruits\Apple; use Fruits\Grape; use Fruits\NoneFruit; $fruitName = getFruitNameByUrlPath(); $fruitData = getFruitData($fruitName); function getFruitNameByUrlPath(){ if(!isset($_GET['fruit'])){ return 'none'; } return $_GET['fruit']; } function getFruitData($fruitName){ $fruit = getFruitInstance($fruitName); $fruitContext = new Fruit($fruit); return $fruitContext->execute(); } function getFruitInstance($fruitName) { switch ($fruitName) { case 'orange': return new Orange; case 'apple': return new Apple; case 'grape': return new Grape; default: return new NoneFruit; } } ?> <?php echo "<table border = '1'>"; echo " <tr>"; echo " <th>名前</th>"; echo " <th>色</th>"; echo " <th>好き or 嫌い</th>"; echo " <th>人気順位</th>"; echo " </tr>"; echo " <tr>"; echo " <th>$fruitData[name]</th>"; echo " <th>$fruitData[color]</th>"; echo " <th>$fruitData[has_like]</th>"; echo " <th>$fruitData[order_of_popularity]</th>"; echo " </tr>"; echo "</table>"; ?>setFruitData()で、それぞれの果物クラスをコンテキストクラスに渡して、メソッドを実行しています。
index.phpfunction getFruitData($fruitName){ $fruit = getFruitInstance($fruitName); $fruitContext = new Fruit($fruit); return $fruitContext->execute(); }これで、以下のようにパラメーターに合わせた果物の情報の表示ができました。
余談
1つ目
ちなみに、コンテキストクラスをこのように書けば、
Fruit.php<?php namespace Fruits; require_once('./Interfaces/FruitInterface.php'); use Interfaces\FruitInterface; class Fruit { private $fruit; public function __construct(FruitInterface $fruit) { $this->fruit = $fruit; } public function getName() { return $this->fruit->getName(); } }クラスを使う側では、名前の取得だけが可能です。
index.phpfunction getName($fruitName){ $fruit = getFruitInstance($fruitName); $fruitContext = new Fruit($fruit); return $fruitContext->getName(); }2つ目
今回は、
getFruitInstance()で、場合分けしてインスタンス生成していますが、
使いたい時にそれぞれのインスタンスを明示的に生成してあげて利用することもできます。index.phpfunction getOrangeData(){ $orange = new Orange; $fruitContext = new Fruit($orange); return $fruitContext->execute(); }














