読者です 読者をやめる 読者になる 読者になる

かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

PHP count(false)は1になる。

WordPressの関数などで、wp_get_attachment_image_srcなど、存在すれば配列が、存在しない時はfalseが返ってくようなものがあります。このような関数を使っている所で、返ってきた値の有無を確認するのにcount()を使っていると予期しないバグを発生させてしまいます。

バグになる例

<?php
$thumbID = get_post_thumbnail_id( $postID );
$thumbData = wp_get_attachment_image_src($thumbID);
if( count( $thumbData ) ) {
  echo '<img src="' . $thumbData[0] . '">';
} else {
  echo 'アイキャッチ画像がありません。';
}

上の例は、アイキャッチが設定されていない投稿でもimgタグが出力されてしまいます。

count(false) が 1になるのが原因

上の例の値をvar_dumpしてみると下記の様になります。

<?php
$thumbID = get_post_thumbnail_id( $postID );
$thumbData = wp_get_attachment_image_src($thumbID);

var_dump( $thumbData );  // false
var_dump( count( $thumbData ) ) // 1

PHPのマニュアルには下記のようにありました。

もしパラメータが配列もしくは Countable インターフェイスを実装したオブジェクトではない場合、 1 が返されます。 ひとつ例外があり、引数 が NULL の場合、 0 が返されます。

ざっくり言えばcount()の引数に配列でないものを渡したとき、引数がnullの場合以外は1が返る仕様のようです。
なので、上記のようにfalseが返ってくる関数の場合、有無を調べるなら、is_arrayか値をそのままif文に入れるのが良さそうです。

うまく動作する例

<?php
$thumbID = get_post_thumbnail_id( $postID );
$thumbData = wp_get_attachment_image_src($thumbID);
if( $thumbData ) { // 又は if( is_array($thumbData) ) 又は if( $thumbData !== false )
  echo '<img src="' . $thumbData[0] . '">';
} else {
  echo 'アイキャッチ画像がありません。';
}

isset( false )true になるのでダメです。


count(), isset() 挙動のメモ

<?php
$val;
var_dump( isset($val) ); // false
var_dump( count($val) ); // 0

$val = false;
var_dump( isset($val) ); // true
var_dump( count($val) ); // 1

$val = [];
var_dump( isset($val) ); // true
var_dump( count($val) ); // 0

01もカウントできないので、count(0)count(1)1になるので、
count(0) === count(1)trueになる。

<?php
$res = ( count(0) === count(1) )? true : false;
var_dump( $res ); // true

// count(100)も 1 なので結果は同じ
$res = ( count(0) === count(100) )? true : false;
var_dump( $res ); // true

 
trueでもfalseでもBool値を保持するのに1単位の領域が必要になるので、count すると 1 になる。
という考え方のようです。
そういえば、MySQLでBOOLEANのカラムがTINYINT(1)になるのと似てる気がしました。


[参考]