ACF用のcalculated-fields-for-acf-kaiでの「条件演算子」で疑似的な条件分岐をおこなう下調べを研究(GTP)
ポイント:
- calculated-fields-for-acf-kaiのFormulaフィールドに数値以外の値を入れた場合、その値はすべて数値の0.0として扱われる。
- これによりPHP8での非数値演算エラーは発生しない。
calculated-fields-for-acf-kai:オリジナルのエラー
- エラーは、PHP 8.0以降の型チェック強化が原因で、古いプラグイン(calculated-fields-for-acf)が未対応の記述をしているために発生
- 数値(float)と文字列(string)を掛け算しようとした
- PHP 7 までは、 ‘5’ * 2 のような処理は自動的に数値変換
>$val = “abc” * 2; // 0 になる(警告すら出ない場合も) - PHP 8以降では「数値に変換できない文字列を演算に使うと致命的エラー」
>$val = “abc” * 2; // 警告: A non-numeric value encountered
- PHP 7 までは、 ‘5’ * 2 のような処理は自動的に数値変換
- 重要:PHP 8以降は「演算子を使うすべての数値演算」で、非数値が混ざるとエラー(または警告)になる。
calculated-fields-for-acf-kai:コードの修正
- EvalMath.phpテンプレートを修正する
- オリジナル:$op1 または $op2 のどちらか、または両方が 数値以外(例:”abc”や空文字) になっている状態で掛け算が実行=結果/float * string という不正演算>エラーの原因
- 修正:演算前に、数値でない場合は強制的に数値にキャスト(連携)する処理を加える
- 演算の前に $op1 と $op2 を強制的に (float) キャストする
- $op1 や $op2 が ‘abc’ のような文字列や空白だった場合 (float) によって自動的に 0.0 と変更する
- 0ではなく、0.0にする理由はGTPを参照する
EvalMath.php:コードの修正点
オリジナルコード
foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, ['+', '-', '*', '/', '^', '%', '==', '!=', '>', '<', '>=', '<='])) {
if (is_null($op2 = $stack->pop())) {
return $this->trigger("internal error");
}
if (is_null($op1 = $stack->pop())) {
return $this->trigger("internal error");
}
// ここから下の箇所がエラー原因:非数値を式に入れて計算実行が可能
switch ($token) {
case '+':
$stack->push($op1+$op2); break;
case '-':
$stack->push($op1-$op2); break;
case '*':
$stack->push($op1*$op2); break;
case '/':
if ($op2 == 0) {
return $this->trigger("division by zero");
}
$stack->push($op1/$op2); break;
case '^':
$stack->push(pow($op1, $op2)); break;
case '%':
$stack->push($op1%$op2); break;
case '==':
$stack->push($op1 == $op2 ? 1 : 0); break;
case '!=':
$stack->push($op1 != $op2 ? 1 : 0); break;
case '>':
$stack->push($op1 > $op2 ? 1 : 0); break;
case '<':
$stack->push($op1 < $op2 ? 1 : 0); break;
case '>=':
$stack->push($op1 >= $op2 ? 1 : 0); break;
case '<=':
$stack->push($op1 <= $op2 ? 1 : 0); break;
}
修正コード
foreach ($tokens as $token) { // nice and easy
// if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
if (in_array($token, ['+', '-', '*', '/', '^', '%', '==', '!=', '>', '<', '>=', '<='])) {
if (is_null($op2 = $stack->pop())) {
return $this->trigger("internal error");
}
if (is_null($op1 = $stack->pop())) {
return $this->trigger("internal error");
}
// 修正:非数値や空白がある場合、強制的に数値(float)(=0.0)に置き換える
// この処理により、PHP8の要件である「数値以外(例:”文字列”や空文字)での計算(=四則演算、剰余、累乗=すべての計算)」を回避する
switch ($token) {
case '+':
$stack->push((float)$op1 + (float)$op2);
break;
case '-':
$stack->push((float)$op1 - (float)$op2);
break;
case '*':
$stack->push((float)$op1 * (float)$op2);
break;
case '/':
if ((float)$op2 == 0) {
return $this->trigger("division by zero");
}
$stack->push((float)$op1 / (float)$op2);
break;
case '^':
$stack->push(pow((float)$op1, (float)$op2));
break;
case '%':
$stack->push(fmod((float)$op1, (float)$op2));
break;
case '==':
$stack->push(((float)$op1 == (float)$op2) ? 1 : 0);
break;
case '!=':
$stack->push(((float)$op1 != (float)$op2) ? 1 : 0);
break;
case '>':
$stack->push(((float)$op1 > (float)$op2) ? 1 : 0);
break;
case '<':
$stack->push(((float)$op1 < (float)$op2) ? 1 : 0);
break;
case '>=':
$stack->push(((float)$op1 >= (float)$op2) ? 1 : 0);
break;
case '<=':
$stack->push(((float)$op1 <= (float)$op2) ? 1 : 0);
break;
}
// 修正ここまで
- ★戻り値の形式=ラベル
値/ラベル/両方 (配列)
戻り値を指定します - ラジオボタンなど(単一選択):
- Value:値(例:「red」)が文字列で返されます。?
- Label:ラベル(例:「赤」)が文字列で返されます。?
- 値 : ラベル
- ★初期値
- 選択肢を表示する「Select」フィールドでは、「デフォルト値」設定で初期選択肢を選びます。