エンジニアのひよこ_level10

毎日更新してた人。たまに記事書きます。

エルビス演算子(?:)で代入とかをスマートに書く【739日目】

if文で代入を書く

if ($user) {
    $item = $user;
} else {
    $item = $request['user'];
}

もし、$userがtrue相当だったときには$userを代入し、
そうでなければ別な値を使う。

よく書くif文ですね。

if ($user) {
    return $user;
} else {
    return $request['user'];
}

こんなのもありますね。

これをエルビス演算子をつかって書き換える

エルビス演算子で書き換え

$item = $user ?: $request['user'];

これですっきり。

おまけ: null合体演算子

undefinedとかを考慮してissetを使いたい場合は、null合体演算子を使うと良さそう

$item = $user ?? $request['user'];

【PHP】無名関数・クロージャ。変数に関数を入れたり出来る【734日目】

変数に関数

こんなコードを見たことはありませんか。

$func = function ($num) {
    return $num *2;
};
$arr = [
    'id'  => 1,
    'item' => function ($num) {
                return $num *  2;
             }
];
$mul_num = 3;

$func_use = function ($num) use ($mul_num) {
    return $num * $mul_num * 2;
};

こんなふうに、メソッドとかじゃなく、
functionだけで書かれていたり、
そのfunctionを変数に入れていたり。

公式ドキュメント

https://www.php.net/manual/ja/functions.anonymous.php

無名関数・クロージャ

無名関数や、クロージャと呼ばれているものです。

$func = function ($num) {
    return $num *2;
};

この時点で、$funcには、 Closureというクラスが入れられています。
間違えてはいけないのは、『まだ実行はされていなくて、Closureというクラスのインスタンスがある』ということ。
つまり、『実行は後で行われる』のです。

実際に実行する

ではどう扱うのか。

echo $func(3); // 結果は6って出る

$funcの中身を見るとわかりますが、$numに3が代入され、実際に動作がされます。

あくまで実行するものを保存するのであって、実行はあとで行われるのですね。

よくある質問。

Q. function ($num)の値は何が入るんだ
A. 動かす瞬間に代入された値で決まります
Q.  呼び出す前に別の所で使ってた値をクロージャ内で使いたい
A. useを使います。下の例のような感じです。
$num_x = 3;

$func = function ($num) use ($num_x) {
    return $num * $num_x;
}

echo $func(6); //18が出る  

【PHP】改行文字を<br>に変更して表示させる【721日目】

改行を使いたい

画面に文字を表示させたい。

このとき、DBなど外部から改行の入った文字が取得出来たとする

こんにちは
はじめまして

これをHTMLとして出力するときに、 <p><?php echo $string ?></p>とするとどうなるか。

<p>こんにちは
はじめまして</p>

HTMLの改行は意味がないので

こんにちは はじめまして

一行になりますね。どうするか

nl2br

<p><?php echo nl2br($string) ?></p>

これでよい。改行文字が nl2br関数を通すことによって、 <br>タグに変わります。

ちなみにLaravelのBladeでやる場合

{!! nl2br(e($string)) !!}

こう書くと良いです。

【PHP】abstractクラスにfinalオプションを付けるとどうなる?【718日目】

abstractクラス

抽象クラス。

なんで抽象クラスと呼ばれるものかは割愛。

このままでは実態がなく、インスタンス化出来ないので、継承とかをして具体的なクラスにしないといけない。

final

これ以上クラスが変動することはないよというオプション。

変数なら代入がされず、クラスなら継承が出来ない。

矛盾が発生する

これは矛盾が発生している。

作っても、クラスの価値がないのでは。

ではどうなるか

エラーが発生する

php > abstract final class uiro {}

Fatal error: Cannot use the final modifier on an abstract class in php shell code on line

まあ、動かないですよね。

ということで、意味のないものはちゃんとPHPで弾いてもらえるそうです。

【PHP】traitでオーバーライド元の関数を使いたいとき【712日目】

traitを拡張したい

Laravelの中にあるtraitを拡張したいとか、traitをさらに継承するように使いたい。

use Illuminate\Foundation\Auth\AuthenticatesUsers as BaseAuthenticatesUsers;

trait AuthenticatesUsers {
    use BaseAuthenticatesUsers
}

こんな感じ。

でも、オーバーライドすると、元のコードが呼び出せない。だって継承じゃないから。
traitは継承が出来ないので悩むところ。さてどうするか。

use Illuminate\Foundation\Auth\AuthenticatesUsers as BaseAuthenticatesUsers;

trait AuthenticatesUsers
{
    use BaseAuthenticatesUsers

    public function login() {
        // 任意の処理

        // 元コードのloginをbase_loginって名前に書き換えるとかして書きたい
        // return base_login();
    }

traitの任意関数に名前をつける

    use BaseAuthenticatesUsers {
        BaseAuthenticatesUsers::login as base_login;
    }

この様に、対象となる クラス名::関数名 as 置換後の関数名で、関数名を置き換えることが出来る

use Illuminate\Foundation\Auth\AuthenticatesUsers as BaseAuthenticatesUsers;

/**
 * Captchaに対応した認証クラス
 * Class AuthenticatesUsers
 * @package App\Libraries\Auth
 */
trait AuthenticatesUsers
{
    use BaseAuthenticatesUsers {
        BaseAuthenticatesUsers::login as base_login;
    }

    public function login() {
        // 任意の処理

        return base_login();
    }

これで、元のコードの関数を動かす前に、任意の処理を書くことが出来るようになった。

公式ドキュメント

https://www.php.net/manual/ja/language.oop5.traits.php

【PHP】PHPとLaravelのバージョンアップで苦しんだのメモ【699日目】

これはメモです

ってことで、改めて後日まとめるかもしれないです。

PHP 7.0->7.1 countの引数

count関数の引数がnullを受け付けなくなりました。

nullが来た場合、配列を入れてくださいってエラーが出ます。

Laravel 5.2->5.3 Paginator.phpのpresenterが消えた

5.2にあった、presenterメソッドが消えてる。

https://github.com/laravel/framework/blob/5.2/src/Illuminate/Pagination/AbstractPaginator.php#L352

viewFactoryResolverに変わっている・・・きがする?

https://github.com/laravel/framework/blob/6.x/src/Illuminate/Pagination/AbstractPaginator.php#L482

ちなみに、paginatorについて変更したと5.3のアップグレードガイドにはありますが、presenterメソッドについては触れられてません。

このメソッドを拡張していた場合は死ぬ(´;ω;`)

【PHP】interfaceは継承・多重継承が可能。読み込みの順番もあり?【697日目】

interfaceの継承

interface A
{
    public function a(string $a, int $b);
}

interface Foo extends A
{
    
}

これ、動きます。Fooはa()の実装を強制出来るinterfaceになりました。

interfaceの多重継承

interface A1
{
    public function a(string $a, int $b);
}

interface A2
{
    public function b(string $a, int $b);
}

interface Foo extends A1, A2
{
    
}

実はこれも動きます。
Fooは、a()とb()の実装を強制出来るinterfaceになりました。

多重継承で、同じメソッドを書いたら?

ではここでクイズ。

interface A1
{
    public function a(string $a, int $b);
}

interface A2
{
    public function a(string $a, int $b);
}

interface Foo extends A1, A2
{
    
}

class Hoge implements Foo {
    public function a(string $a, int $b)
    {
         return true;
    }
}

全く同じ関数名、同じ構成のものを多重継承したら?

これも動きます。ちゃんとHoge動きます。オーバーライドしてるっぽい?

多重継承で、同じメソッドを拡張するように書いたら?

interface A1
{
    public function a(string $a, int $b);
}

interface A2
{
    public function a(string $a, int $b): bool;
}

interface Foo extends A1, A2
{
    
}

class Hoge implements Foo {
    public function a(string $a, int $b): bool
    {
         return true;
    }
}

ではこれは?

なんと動きません。

PHP Fatal error:  Declaration of A1::a(string $a, int $b) must be compatible with A2::a(string $a, int $b): bool in /workspace/Main.php on line 13

A1のメソッド、A2のメソッドの条件に一致していないってなってます。

つまり・・・?

仮設: 多重継承に読み込み順がある?

interface A1
{
    public function a(string $a, int $b): bool;
}

interface A2
{
    public function a(string $a, int $b);
}

interface Foo extends A1, A2
{
    
}

class Hoge implements Foo {
    public function a(string $a, int $b): bool
    {
         return true;
    }
}

なんと、これ動きます。

これは仮設ですが、A2をまず継承したあと、A1を定義しているのかもしれません。
A2の条件をA1のメソッドが満たしているので、これは正しく動きます。

ちなみに、関数名変えたり並び替えたりは試したので、クラス名は関係なさそうですφ(・

まだまだPHPわからないことあって面白いですね(‘ω‘ )

【正規表現】()内で `?:`使って、preg_matchなどの検索結果に含めない【690日目】

グルーピングに使う()で不便なこと

正規表現を書くときに、

/(aaa)([0-9])(aaa)/

このように、ひとつのまとまりを表現するために、 ()を使うときがあります。

しかしこのとき、結果を \1などで選択するときには、 ()の数を数えて、何番目かを確かめないといけないです。

今回だと、2番目・・・みたいに考えるのは面倒。(aaa)とか数える順番から除外したい。

php > $text = "aaa2aaa3aaa";
php > preg_match("/(aaa)([0-9])(aaa)/", $text, $matches);
php > var_dump($matches);
array(4) {
  [0]=>
  string(7) "aaa2aaa"
  [1]=>
  string(3) "aaa"
  [2]=>
  string(1) "2"
  [3]=>
  string(3) "aaa"
}

これ嫌ですよね。

()内で?:を使う

php > preg_match("/(?:aaa)([0-9])(?:aaa)/", $text, $matches);
php > var_dump($matches);
array(2) {
  [0]=>
  string(7) "aaa2aaa"
  [1]=>
  string(1) "2"
}

?:を使ったときには順番から除外されていますね!

結構便利φ(・