LoginSignup
3
2

PHP の論理積 (&&) の短絡評価で null check しつつ bool を返す

Last updated at Posted at 2024-06-06

はじめに

PHP は if 文に null 入れると false を返してくる。
そんな中、null check して、null なら falsenull じゃなかったら関数を実行するコードがあり、何も不思議に思わなかったが 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
3
2
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2