• wp_cache_get()がfalseを返したらfoundでcache missか保存値かを分ける

wp_cache_get()がfalseを返したらfoundでcache missか保存値かを分ける

公開日: 執筆:佐藤

WordPressのwp_cache_get()は、cacheに値がない場合も、保存されている値がfalseの場合も、戻り値がfalseになります。戻り値だけを条件式へ入れると、保存済みのfalseをcache missと誤認します。

第4引数の$foundを使ってください。$foundはkeyが見つかればtrue、見つからなければfalseになり、戻り値とは別にcacheの有無を示します。

戻り値とfoundは答える疑問が違う

WordPress 4.0のObject Cache APIでは、wp_cache_get()を次の引数で定義しています。

wp_cache_get( $key, $group = '', $force = false, &$found = null );

各引数の役割を分けます。

引数 役割
$key 保存した値を識別するkey
$group 同じkeyを用途別に分けるgroup。空ならdefaultになる
$force persistent cacheから取り直すようbackendへ求める指定
$found keyがcache内に存在したかを受け取る変数

戻り値は保存されていた値です。$foundは、その値が見つかったかどうかです。値の内容とcacheの状態を、一つのfalseへ押し込まないための引数だと考えると分かりやすくなります。

falseを保存できる処理ではfoundを必ず確認する

次は、外部連携を有効にするかどうかを調べた結果をcacheへ置く仮例です。

$found  = false;
$active = wp_cache_get( 'external_service_active', 'satolab_settings', false, $found );

if ( ! $found ) {
    $active = satolab_check_external_service();
    wp_cache_set( 'external_service_active', $active, 'satolab_settings' );
}

if ( $active ) {
    satolab_run_external_service();
}

satolab_check_external_service()がfalseを返し、その値を保存する場合でも、二回目の取得では$foundがtrueになります。したがって、同じ確認処理を繰り返しません。

次の書き方では、保存済みのfalseとcache missを分けられません。

$active = wp_cache_get( 'external_service_active', 'satolab_settings' );

if ( false === $active ) {
    $active = satolab_check_external_service();
}

戻り値が必ず配列や文字列になる設計なら、falseをmissとして扱える場合もあります。それでも、保存できる値の範囲を関数の責任として決めておかないと、後からbooleanを保存した時点で判定が崩れます。

keyとgroupは保存時と取得時でそろえる

wp_cache_set()で保存した値は、同じ$keyと$groupを指定して取得します。keyが同じでもgroupが違えば別の値です。groupを省略するとdefaultになるため、保存側だけにgroupを書いた状態でもmissになります。

wp_cache_set( 'summary', $summary, 'satolab_reports' );

$found   = false;
$summary = wp_cache_get( 'summary', 'satolab_reports', false, $found );

用途の異なる値を一つのgroupへ集めるより、pluginや機能の責任範囲が分かるgroup名を決めます。削除するときも、wp_cache_delete()へ同じkeyとgroupを渡します。

setとaddとreplaceは上書き条件が違う

Object Cache APIには、保存方法が三つあります。

関数 保存条件
wp_cache_set() keyの有無にかかわらず値を保存する
wp_cache_add() keyがまだない場合だけ保存する
wp_cache_replace() keyがすでにある場合だけ置き換える

単に最新の計算結果へ更新するならwp_cache_set()を使います。先に保存された値を残したいならwp_cache_add()、存在確認済みの値だけを更新したいならwp_cache_replace()です。関数名ではなく、上書きを許すかどうかで選びます。

保存の成否を確認する必要がある処理では、それぞれの戻り値も確認してください。$foundが示すのは取得時の存在であり、直前の保存が成功したかどうかではありません。

default cacheはrequestをまたぐ保存を保証しない

WordPress 4.0の標準WP_Object_Cacheは、値をmemoryへ置き、PHPの処理が終わると失います。$expireも標準実装では使いません。persistent cacheの実装へ置き換えられている環境では、requestをまたいで値が残り、$forceや期限の扱いもbackendに依存します。

そのため、Object Cacheへ入れた値が次のrequestにも必ず残る前提では設計しません。消えたら元データから再生成できる値に限り、cacheを速さのための手段として使います。保存そのものが目的なら、databaseやfileなど、必要な耐久性を持つ保存先を選びます。

foundは権限確認やnonce確認の代わりにならない

$foundが答えるのは、cache keyが存在したかどうかだけです。管理画面から更新処理を実行してよい利用者か、正しい画面から送られたrequestかは答えません。

利用者の操作でcacheを更新または削除する処理では、権限とnonceを別に確認します。cacheの存在判定、requestの正当性、保存元データの正しさは、異なる問題です。

最初の一手は、wp_cache_get()の戻り値だけでmissを判定している箇所を探し、保存され得る値にfalseが含まれるかを確認することです。含まれるなら、第4引数の$foundを追加します。

戻る