はじめに
PHP は if
文に null
入れると false
を返してくる。
そんな中、null check して、null
なら false
、null
じゃなかったら関数を実行するコードがあり、何も不思議に思わなかったが IDE がもっといい書き方あるぜって言ってきた。
$is_smartphone = $client_type ? $client_type->isSmartphone() : false;
自動変換してもらったらこうなった。
$is_smartphone = $client_type && $client_type->isSmartphone();
.....。
null check どこいった?false
どうやって入る?って思ってちょっと調べた。
追記: 記事最下部に PHP 8.0 以降の書き方も紹介しています。
PHP の論理積 (&&)
どうやら PHP では、左の評価をして否定されたら終わるという実行形式らしい。これ短絡評価っていうみたい。
PHP では null
がきたら false
で返してくれるので、左側に null check を置くことができる。
$classVar = null;
// $classVar = null は false になるなので、
// 短絡評価により$classVar->isVar(); は実行されない。
$var = $classVar && $classVar->isVar();
// $var = false となる
$classVar = new ClassVar(true);
// $classVar は true になるなので、
// 短絡評価は関係なく $classVar->isVar(); が実行される
$var = $classVar && $classVar->isVar();
// $var = true となる
つまり、左側に null
、つまり false
になると右が実行されないので、実質的に null check できるのである。
おわり
null check した上で関数などの bool 値を評価したいときは、短絡評価を上手く使ってやるときれいに書けそう!
// before
$is_smartphone = $client_type ? $client_type->isSmartphone() : false;
// after
$is_smartphone = $client_type && $client_type->isSmartphone();
追記 (24/06/07)
PHP 8.0 以降であればこのような書き方ができるので、合わせて抑えておきましょう!
(@dgcdsbsd2 , @YuneKichi, @haikara さんありがとうございます!( *・ω・)*_ _)))
$is_smartphone = $client_type?->isSmartphone() ?? false;
検証してみたのでコードも合わせて置いておきます。
<?php
class ClassVar {
private bool $isVar;
public function __construct(bool $isVar){
$this->isVar = $isVar;
}
public function isVar(): bool {
return $this->isVar;
}
}
function println(string $str, string $type, mixed $bl): void {
print_r("$str ($type): ");
if ($bl === true) {
print_r("true");
} else {
print_r("false");
}
print_r("\n");
}
// --
// 1: 短絡評価 (エラーなく true/false が入る) (?int だとバグる可能性あり)
// 2: PHP 7.0~ の ?? のみ (2 行必要になりそう (null check → メソッド実行))
// 3: PHP 8.x~ の ?-> のみ (null のとき NULL 型が入る)
// 4: ?-> と ?? をあわせる (PHP 8.0 以降なら一番良いかも?)
// --
$classVar = null;
$res = $classVar && $classVar->isVar();
println("null 1", gettype($res), $res);
// null 1 (boolean): false
$res = $classVar->isVar() ?? false;
println("null 2", gettype($res), $res);
// Fatal error: Uncaught Error: Call to a member function isVar() on null
$res = $classVar?->isVar();
println("null 3", gettype($res), $res);
// null 3 (NULL): false
$res = $classVar?->isVar() ?? false;
println("null 4", gettype($res), $res);
// null 4 (boolean): false
$classVar = new ClassVar(true);
$res = $classVar && $classVar->isVar();
println("new 1", gettype($res), $res);
// new 1 (boolean): true
$res = $classVar->isVar() ?? false;
println("new 2", gettype($res), $res);
// new 2 (boolean): true
$res = $classVar?->isVar();
println("new 3", gettype($res), $res);
// new 3 (boolean): true
$res = $classVar?->isVar() ?? false;
println("new 4", gettype($res), $res);
// new 4 (boolean): true