20200107のPHPに関する記事は19件です。

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と記入する。


参考

https://stackoverflow.com/questions/28739818/php-how-to-add-leading-zeros-zero-padding-to-float-via-sprintf

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【未経験エンジニア2日目(復習①)】URLの.htmlの削除

URLの.htmlの削除

やったこと

・URLの.htmlの削除

学んだこと

hraccessの存在

RewriteRule

 ディレクトリー内のURLを正規表現を用いて定義をすることができる

RewriteCond

 RewriteRuleの条件を絞るこむために記載される(RewriteRuleの直前に記載される) 

実際のコード

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html

参考サイト

.phpや.htmlなどの拡張子をURL表示させない方法
.htaccess でのリダイレクト(転送)設定の書き方

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 関数の作り方

目的

  • PHPでの関数の作り方をまとめる

書き方の例

  • 下記に関数の定義方法を記載する。
//関数の定義(引数の有無に関わらず括弧をつけて変数を定義する)
function 関数名(第一引数を格納する変数A, 第二引数を格納する変数B){
  関数内で実行する処理;
}

//関数の呼び出し(定義時に引数が格納される変数の定義の有無に関わらず括弧をつけて呼び出す)
関数名(第一引数, 第二引数);
  • 関数内での結果を変数に格納したい
//関数の定義
function 関数名(第一引数を格納する変数A, 第二引数を格納する変数B){
  return 任意の処理;
}

$foo = 関数名(第一引数, 第二引数);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 日付関連の処理を施す

Carbonはphpに標準で存在するDateTimeクラスを拡張して、日付操作をより簡単にしてくれます。

まず、composerにCarbonをインストールしましょう。

composer self-update

//composer --versionでバージョンの確認ができます。

そしたら、composerにCarbonをインストールしましょう。

composer require nesbot/carbon

現在地点からの日時取得

hogehogeController.php
use 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/

上記サイトにほとんど書いてあるので、参考にしてみましょう!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ちょっとお兄ちゃん?否定のフラグは絶対作らないでって言ったよね?

(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」みたいにしてあげると後々嬉しいことが多いです

まとめ

否定のフラグを作ってしまいそうになったら肯定のフラグに作り直しましょう

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Joker123およびS128の最新のオンラインゲームゲームをプレイする

簡単な勝利の闘鶏オンラインS128のヒントとコツ

闘鶏のゲームでは、1回のプレイでアリーナに2羽の鶏が集まります。 2羽の鶏が1つのアリーナに置かれたので、次に何が起こるか推測できます。

闘鶏(英語)で訳されている場合、鶏と戦う(雄鶏と戦う)または他の名前の鶏(闘鶏)または雄鶏と戦う(雄鶏と闘う/闘う/闘う)。英語の翻訳では、「Bangkok Chicken」という用語は使用していません。バンコクバンコクコックファイトという用語は、実際には、首都がバンコクであるタイの国から最初に来た鶏の種類のローカル指定です。バンコクの鶏は格闘闘争になるキャラクターと本能を持っています。

タイでは、鶏はタイまたはタイの鶏と名付けられ、他の種類の戦いの鶏も、ベトナムやビルマ/ビルマ(ミャンマー)の鶏など、最初に発見された国の名前に基づいて名付けられます。

0_SWQkSVIR4ElKK3hL.png

簡単に勝利するためのヒントとコツ闘鶏をオンラインでプレイする
S128チキンオンラインでのコックファイトに勝つために、次のステップを検討してください。

1.インストールする前に鶏肉の種類を慎重に選択してください
闘鶏ゲームのゲームで本当に必要なのは、闘鶏アリーナでヒーローとなる格闘鶏を選ぶ際の注意です。

2.安全で信頼性の高い闘鶏エージェントサイトの選択
信頼できるサイトはデータのセキュリティも保証するため、オンラインギャンブルサイトの選択では、それは偶然ではなく、オンラインギャンブルのゲームのサイトの主力であるべきです。また、資金の支払いは迅速に処理され、すべてにエラーはありません払い戻し処理プロセス。 JENEBT.INFO は、入金、登録、出金などのすべてのプロセスにおける信頼できる高速の闘鶏エージェントの例であり、すでにアジアで記録を保持しています。

3.闘鶏に十分な速さのインターネット接続を使用する
ライブ/ライブストリーミングで提供される闘鶏製品は、インターネット接続が常に安定しており、接続の切断を防止しないようにする必要があります。それが望ましくない場合は、闘鶏のゲームを見逃すことが確実です闘鶏試合で負ける可能性があります。S128 オンライン闘鶏のゲームでは、生きている闘鶏試合に勝つために必要であるため、プレイヤーには認識が本当に必要です。

コックファイティングオンラインで簡単に勝つためのトリックの適用

4.プレイするとき感情になるのは簡単ではありません
あなたがコックファイトでプレーするとき、あなたは感情的に簡単にコントロールされている場合、試合を見る集中力が分かれているか焦点が合っていないので、少しの間夢中になってはいけません。ハードか何でも。

5.プレイしたいときに予算を調整します
オンライン闘鶏のゲームでは、デポジットを行う前に最小ベット/ベットを確認する必要があり、ゲームに1から2ラウンド渡すだけで、必要なデポジット額に応じてベットを開始し、最小ベット/ベットに調整する必要がありますこれは、Joker123 などの各オンライン闘鶏エージェントによって調整されています。

0_HXRDcv9cbeQtkRub.jpg

今回共有したコックファイティングの主力戦で勝つためのヒントと簡単なコツが、オンラインコックファイティングゲームであるWarm Regards Online Cockfighting Agent、JNEBET.INFO で勝つ方法を知る上での洞察に役立つことを願っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

larave-adminでcheckboxをDBに保存

larave-adminはお手軽にさらっと管理画面を作れて便利です。
大まかな使用方法は他の記事にお任せするとしてcheckboxmultiselectなどをDBに保存するにはひと手間必要なので備忘録的メモです

公式に記述があります。二つあるようですが今回はデータをカンマ区切りで登録する方法です。
https://laravel-admin.org/docs/#/en/model-form-fields

class Post extends Model

    public function getTagsAttribute($value)
    {
        return explode(',', $value);
    }

    public function setTagsAttribute($value)
    {
        $this->attributes['tags'] = implode(',', $value);
    }
}

そのまま引用しています。get[elements]Attributeset[elements]Attributeをoverwriteしています。

マイグレーションはtextかvarcharあたりで

            Schema::create('post', function (Blueprint $table) {
                $table->bigIncrements('id');

                $table->text('tag');
                $table->timestamps();
                $table->softDeletes();

            });

これでDBにはカンマ区切りで保存されます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel-adminでcheckboxをDBに保存

larave-adminはお手軽にさらっと管理画面を作れて便利です。
大まかな使用方法は他の記事にお任せするとしてcheckboxmultiselectなどをDBに保存するにはひと手間必要なので備忘録的メモです

公式に記述があります。二つあるようですが今回はデータをカンマ区切りで登録する方法です。
https://laravel-admin.org/docs/#/en/model-form-fields

class Post extends Model

    public function getTagsAttribute($value)
    {
        return explode(',', $value);
    }

    public function setTagsAttribute($value)
    {
        $this->attributes['tags'] = implode(',', $value);
    }
}

そのまま引用しています。get[elements]Attributeset[elements]Attributeをoverwriteしています。

マイグレーションはtextかvarcharあたりで

            Schema::create('post', function (Blueprint $table) {
                $table->bigIncrements('id');

                $table->text('tag');
                $table->timestamps();
                $table->softDeletes();

            });

これでDBにはカンマ区切りで保存されます

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 HasApiToken you can add the new trait HasUuid

class User extends Authenticatable
{
    use HasApiTokens, Notifiable, SoftDeletes, HasUuid;
    ....

残りは、APIの作成方法に関する以前のチュートリアルに従うことができます

The rest you can follow my previous tutorials on how to create an API

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

クラスとは

「クラス」とは

よく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 はメソッドの定義の中でのみ使用できる、特殊な変数です。
このときプロパティ名に$(ダラー)はつけません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのバリデーションで、正規表現のパイプが使えない件

Laravelのバリデーションで、正規表現のパイプが使えない件

Laravelのバリデーション

Laravelには、いくつかのバリデーションルールが用意されており、パイプ区切りで実行したいルールをvalidateメソッドへ渡すことで、複数のルールを利用することができる。

[バリデーションルールの例]

ルール 説明
email フィールドがメールアドレスとして正しいことをバリデートする
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:/(大阪|東京)/'],
  ];
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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点です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今年できるようになったこと・来年の目標

はじめに

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/サブネット/AZ

Systems 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ツールについてしっかり知っておきたいので空き時間に触っていこうと思います。

まとめ

想像より時間がかかりましたが、自分の知識がどれほど身についているか、どこがまだわからないのかなどがはっきりするため、知識の棚卸は大切だと感じました。
今年中にしっかりと上記の目標を達成できるように空き時間を有効に使っていこうと思います!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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()の実装を見ていくと、以下の順に処理をしていることがわかります。

  1. \Magento\Catalog\Model\Product\Url::getProductUrl()
  2. \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で含める。

というほんの僅かな対応で解決できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【 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.jpg


【 LaravelDB.comの POINT!! 】

ER図を作成していきますが重要事項があります!

<<重要>>
主キーのAutoIncrementは どのテーブルも『 id 』 と固定すること!!

image.png

LaravelのEloquentModel を便利に使うためには、どのテーブルも 『 id 』 と固定するのが吉です。
理由は「 モデル名::find($id); 」と便利に使う場合は 主キーのAutoIncrement 『 id 』 名にしておかないと動作しないからです( Laravelを勉強してる人はなんとなく知ってることでしょうか )。
※ laravelDB.comのCRUDでも生成されるファイルは「 ○○○::find($id); 」を使ってるためそ!
※ laravelに最初から入っているテーブル「user」「password_resets」は作成しないこと(migrate時に上書きしてしまいます)
※慣れれば簡単ですが、少しだけ慣れる時間は必要ですね。


【 CRUDを生成してみる! 】

まずは、ER図を簡単に作ってみましょう!!
その後に右メニュー「 ER図のLoad/Save 」をクリックすると以下画面が表示されます。
image.png
CRUDを生成するボタンが新しく出来ています!!!
※まだデバッグが全て終わってないため「BETA」と書いてますが、クリックです!!!


【 CRUD: 新しいプロジェクトを用意 】

最低限Laravelがインストールした状態 を準備します!
image.png


【 CRUD: ダウンロードファイルを確認しましょう 】

Zip圧縮ファイルがダウンロードされるので、Zipを展開(解凍)して中を見てみましょう!
CRUDに必要なファイルが一式入っています。
image.png
ダウンロードしたファイル( 各フォルダ内のファイル )を移動しましょう!
※welcome.blade.phpはダウンロードしたファイルへのリンクが生成されているので、上書きしてください。


【 CRUD: 配置しおわったら「 Migrate 」しましょう 】

DBや.env設定など最低限の設定が終わっていたら

php artisan migrate

で、テーブルを作成してください。


【 完成: ブラウザで確認しましょう! 】

http://localhost/ (URLは開発環境によって異なります) で確認しましょう!
画面の中央に今までなかったリンクが出来ています。あなたが作ったテーブルのCRUD画面へ遷移できますよ!!

image.png


画面が古いままの場合(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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【 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.jpg


【 LaravelDB.comの POINT!! 】

ER図を作成していきますが重要事項があります!

<<重要>>
主キーのAutoIncrementは どのテーブルも『 id 』 と固定すること!!

image.png

LaravelのEloquentModel を便利に使うためには、どのテーブルも 『 id 』 と固定するのが吉です。
理由は「 モデル名::find($id); 」と便利に使う場合は 主キーのAutoIncrement 『 id 』 名にしておかないと動作しないからです( Laravelを勉強してる人はなんとなく知ってることでしょうか )。
※ laravelDB.comのCRUDでも生成されるファイルは「 ○○○::find($id); 」を使ってるためそ!
※ laravelに最初から入っているテーブル「user」「password_resets」は作成しないこと(migrate時に上書きしてしまいます)
※慣れれば簡単ですが、少しだけ慣れる時間は必要ですね。


【 CRUDを生成してみる! 】

まずは、ER図を簡単に作ってみましょう!!
その後に右メニュー「 ER図のLoad/Save 」をクリックすると以下画面が表示されます。
image.png
CRUDを生成するボタンが新しく出来ています!!!
※まだデバッグが全て終わってないため「BETA」と書いてますが、クリックです!!!


【 CRUD: 新しいプロジェクトを用意 】

最低限Laravelがインストールした状態 を準備します!
image.png
この時点ではまだLOGINは作らないように!


【 CRUD: ダウンロードファイルを確認しましょう 】

Zip圧縮ファイルがダウンロードされるので、Zipを展開(解凍)して中を見てみましょう!
CRUDに必要なファイルが一式入っています。
image.png
ダウンロードしたファイル( 各フォルダ内のファイル )を移動しましょう!
※welcome.blade.phpはダウンロードしたファイルへのリンクが生成されているので、上書きしてください。


【 CRUD: 配置しおわったら「 Migrate 」しましょう 】

DBや.env設定など最低限の設定が終わっていたら

php artisan migrate

で、テーブルを作成してください。


【 完成: ブラウザで確認しましょう! 】

http://localhost/ (URLは開発環境によって異なります) で確認しましょう!
画面の中央に今までなかったリンクが出来ています。あなたが作ったテーブルのCRUD画面へ遷移できますよ!!

welcome.blade.php
image.png

作成されたindex/show/editの画面
基本的な処理が最初から出来てます!捗りそうですね!
image.png


画面が古いままの場合(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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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 === 5TRUEもしくはFALSEと評価されることです。
よって、

$is_number_5 = $number === 5;

var_dump($is_number_5); //bool(true)

となり$is_number_5には$number === 5true評価された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に再代入します。$boolfalseになるまで、すなわち$number5になるまでwhile文は走査されることになります。

論理演算子の仕組み

ここでは論理演算子論理和論理積についてお話します。

前提知識

$number = 5;

$number !== 5 || $number = 1;

echo $number; //1

上記のコードを実行すると、$number1になっていますね!

これは、論理和が左式または右式のどちらかが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に従った構文で書きます。

この時、

  • atrueであれば、aがエルビス演算子の評価
  • afalseであれば、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してはいけません

私自身まだまだ未熟者でありますので、チョットデキル方々お手柔らかにお願いします笑

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【デザインパターン】PHPでStrategyパターンの実装をしてみた

環境

  • PHP 7.2.18

はじめに

今更ながら、デザインパターンを真面目に理解し始めようとしている2年目エンジニアであります。
まずは事始めに「Strategyパターン」から勉強していこうと思い、この記事を書きました。
普通はJavaで勉強すべきだと思うのですが、Java初心者すぎるので、一番触っているPHPで勉強しています。
ちなみに、会社のブログでも同じような記事を書いたので、ここに貼っておきます。
レガシーコードをぶっ壊す!〜基本のキ編〜

Strategyパターンとは

Strategyとは、「戦略」や「作戦」という意味を持ちます。
この「戦略」や「作戦」毎にクラスを分割して、簡単にそれらを切り替えることができるのが特徴です。
共通のインターフェースを定義し、クラスを使う側(以下クライアント)はそれに伴った処理を実行するので、クライアントは具体的な実装に依存しなくなります。
strategyパターンのクラス図は以下のようなものです。
スクリーンショット 2020-01-07 1.19.10.png

Strategyパターンは何がいいか

自分が一番Strategyパターンを使うことで受けたメリットは、if文やswitch文などの複雑な条件分岐をスマートにすることです。
普段であれば場合分けしなければならないところを、「戦略」をクラスに格納することによりコードが非常にシンプルになり可読性や拡張性が上がります。

例題の概要

今回は、例として簡単なプログラムを作りました。
URLのクエリパラメーターから、果物の名前を取得して、その果物の情報を表示しています。
イメージ図とクラス図です。

イメージ図

スクリーンショット 2020-01-07 1.20.28.png

クラス図

スクリーンショット 2020-01-07 1.18.39.png

ファイル構成

スクリーンショット 2020-01-06 23.56.21.png

ソースコード

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.php
function getFruitData($fruitName){
    $fruit = getFruitInstance($fruitName);
    $fruitContext = new Fruit($fruit);
    return $fruitContext->execute();
}

これで、以下のようにパラメーターに合わせた果物の情報の表示ができました。

スクリーンショット 2020-01-07 0.25.29.png

余談

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.php
function getName($fruitName){
    $fruit = getFruitInstance($fruitName);
    $fruitContext = new Fruit($fruit);
    return $fruitContext->getName();
}

2つ目

今回は、 getFruitInstance() で、場合分けしてインスタンス生成していますが、
使いたい時にそれぞれのインスタンスを明示的に生成してあげて利用することもできます。

index.php
function getOrangeData(){
    $orange = new Orange;
    $fruitContext = new Fruit($orange);
    return $fruitContext->execute();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む