タイトル: 代入演算子
SEOタイトル: PHP 代入演算子完全ガイド
| この記事の要点 |
|
基本代入と複合代入
$x = 10;
$x += 5; // 15 (= $x = $x + 5)
$x -= 3; // 12
$x *= 2; // 24
$x /= 4; // 6
$x %= 4; // 2
$x **= 3; // 8 (累乗)
// ビット演算 (整数のみ)
$f = 0b0101;
$f |= 0b1000; // 0b1101
$f &= 0b1100; // 0b1100
$f ^= 0b1010; // 0b0110
$f <<= 2; // 左シフト
$f >>= 1; // 右シフト
// 文字列連結
$s = 'Hello';
$s .= ' World'; // 'Hello World'
// Null 合体代入 (PHP 7.4+)
$config['timeout'] ??= 30;
// = isset($config['timeout']) ? $config['timeout'] : $config['timeout'] = 30
複合代入演算子一覧
| 演算子 | 等価 | 導入 |
|---|---|---|
+= | $a = $a + $b | PHP 4 |
-= | $a = $a - $b | PHP 4 |
*= | $a = $a * $b | PHP 4 |
/= | $a = $a / $b | PHP 4 |
%= | $a = $a % $b | PHP 4 |
.= | $a = $a . $b | PHP 4 |
**= | $a = $a ** $b | PHP 5.6 |
&= |= ^= | ビット AND/OR/XOR | PHP 4 |
<<= >>= | ビットシフト | PHP 4 |
??= | null のときだけ代入 | PHP 7.4 |
参照代入 (&)
$a = 1;
$b = $a; // 値コピー
$b = 99;
echo $a; // 1 (変わらない)
// 参照代入
$a = 1;
$b = &$a; // 同じ実体
$b = 99;
echo $a; // 99 (両方変わる)
// 関数引数の参照
function increment(int &$n): void {
$n++;
}
$x = 5;
increment($x);
echo $x; // 6
// foreach の参照 (要注意)
$arr = [1, 2, 3];
foreach ($arr as &$v) { $v *= 2; }
unset($v); // ★ 忘れると次の foreach でバグる
print_r($arr); // [2, 4, 6]
分割代入 (Destructuring, PHP 7.1+)
// 配列から
[$a, $b, $c] = [1, 2, 3];
// または list($a, $b, $c) = [1, 2, 3];
// 連想配列から (キー指定)
['name' => $name, 'age' => $age] = ['name' => 'taro', 'age' => 20];
// スキップ
[, , $third] = [1, 2, 3]; // $third = 3
// ネスト
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
// foreach での利用
$users = [
['name' => 'taro', 'age' => 20],
['name' => 'jiro', 'age' => 25],
];
foreach ($users as ['name' => $name, 'age' => $age]) {
echo "$name: $age\n";
}
// 関数戻り値の分割
function range2(): array {
return [0, 100];
}
[$min, $max] = range2();
連鎖代入
// 右から左に評価される
$a = $b = $c = 0;
// = $a = ($b = ($c = 0));
// 全部 0 になる
echo $a, $b, $c; // 000
// 連鎖はクリアな意図のときだけ。複雑なら避ける
値コピー vs 参照コピー
// 配列: 値コピー (Copy on Write)
$arr1 = [1, 2, 3];
$arr2 = $arr1;
$arr2[] = 4;
print_r($arr1); // [1, 2, 3] (変わらない)
print_r($arr2); // [1, 2, 3, 4]
// オブジェクト: 参照コピー (PHP の仕様)
class Box { public int $v = 0; }
$b1 = new Box();
$b2 = $b1;
$b2->v = 99;
echo $b1->v; // 99 ! 両方同じ
// オブジェクトを「コピー」したいなら clone
$b3 = clone $b1;
$b3->v = 0;
echo $b1->v; // 99 (変わらない)
Type Coercion (型変換) の罠
$x = '5' + 3; // 8 (PHP 7) / 8 (PHP 8 だが Deprecated 警告)
$x = '5abc' + 3; // 8 (PHP 7 警告) / TypeError (PHP 8)
$x = 'abc' + 3; // 3 + warning (PHP 7) / TypeError (PHP 8)
// 厳密に書く
$x = (int) '5' + 3; // 8
$x = intval('5') + 3; // 8
// 文字列連結との混同
$x = 1 + 2 . 3;
// PHP 7: '33' (1+2=3, '3'.'3'='33')
// PHP 8: Deprecated (・ は + より弱い)。括弧推奨
$x = (1 + 2) . 3; // '33' (明示)
null と false と 0 と "" の代入
$a = null;
$b = false;
$c = 0;
$d = '';
// 緩い比較なら全部等しい
var_dump($a == $b); // true
var_dump($b == $c); // true
var_dump($c == $d); // PHP 7: true / PHP 8: false (仕様変更)
// 厳密比較なら全部別物
var_dump($a === $b); // false
var_dump($b === $c); // false
var_dump($c === $d); // false
// 推奨: 「未入力」判定は厳密比較
if ($input === null || $input === '') {
/* 未入力 */
}
FAQ
Q: $a = $b でオブジェクトをコピーしたい
A: clone を使います。$a = clone $b。深いコピーが必要なら __clone() を実装するか、シリアライズで丸ごとコピー。
Q: 参照渡しと値渡し、どちらを使うべき?
A: PHP は通常値渡しで十分速い (Copy on Write)。参照は意図的に呼び出し元を変更したいときだけ。
Q: 分割代入で「キーが存在しない」場合は?
A: 警告が出て null が代入されます。PHP 7.4+ なら ['name' => $n = 'default'] = ... のようなデフォルトは書けません (関数引数のみ)。