---
title: PHPの「＝」は本当にコピーしているのか？
tags: 
author: [Kou](https://docswell.com/user/kou_tech)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/87DX4236EG.jpg?width=480
description: PHPの「＝」は本当にコピーしているのか？ by Kou
published: October 18, 25
canonical: https://docswell.com/s/kou_tech/5N93XP-2025-10-18-213632
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/87DX4236EG.jpg)

PHPの「＝」は本当にコピーしているのか？
発表者: Kou
イベント: 第6回 札幌PHP勉強会
1


# Page. 2

![Page Image](https://bcdn.docswell.com/page/VJPPM1PZJ8.jpg)

自己紹介
Kou
札幌市内のプログラマー
Sapporo Engineer Base運営
スキル：PHP、React、Azure
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/2EV29Y2MEQ.jpg)

はじめに
普段は Laravel 中心で開発
言語そのものの挙動は意外と曖昧になりがち
本日はPHPの配列と文字列の「＝(代入)」を軸に Copy on Write (COW) を説明
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/57GRZ9RXEL.jpg)

コードで動作確認
$a = [1, 2, 3];
$b = $a;
$b[0] = 99;
var_dump($a); // [1, 2, 3]
var_dump($b); // [99, 2, 3]
の出力は [1,2,3] のまま → 「値渡し」っぽく見える
でも実際は $b = $a; の時点でコピーは行われていない
$a
4


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4EQVLWV5JP.jpg)

Copy on Write（COW）
代入時にはコピーせず、書き換えが起こったときに初めてコピーする
$b = $a; の時点では同じメモリアドレスを共有
$b[0] = 99; の時点で実体を複製
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/KJ4MDKMVE1.jpg)

zvalとrefcountの基礎
zval (Zend value)… PHPの任意の値を表現する内部構造
主な情報
value （実体 or 参照先）
type （型タグ）
refcount （参照カウント）
is_ref （参照共有か）
PHP7で zvalは軽量構造体 にリファクタリング。
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/LE18ZX847G.jpg)

① 配列 COW（書き込み前）
$a = [1, 2, 3];
$b = $a;
echo &quot;== 書き込み前 ==\n&quot;;
xdebug_debug_zval(&#039;a&#039;);
xdebug_debug_zval(&#039;b&#039;);
期待される表示
a: (refcount=2, is_ref=0)=array(...)
b: (refcount=2, is_ref=0)=array(...)
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/GEWZ9NZZE2.jpg)

配列 COW （書き込み後）
$b[0] = 99; // ★ここでCOW発動
echo &quot;== 書き込み後 ==\n&quot;;
xdebug_debug_zval(&#039;a&#039;);
xdebug_debug_zval(&#039;b&#039;);
期待表示
a: (refcount=1, is_ref=0)=array(...)
b: (refcount=1, is_ref=0)=array(...)
書き込んだ瞬間に 分離（コピーが発生）
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/47Z1931LJ3.jpg)

② 参照渡しは COW を無効化
$a = [1, 2, 3];
$b =&amp; $a; // 明示参照
xdebug_debug_zval(&#039;a&#039;);
xdebug_debug_zval(&#039;b&#039;);
期待表示
a: (refcount=2, is_ref=1)=array(...)
b: (refcount=2, is_ref=1)=array(...)
同一zvalを共有し続ける → どちらを変更しても両方に反映
「参照渡し＝速い」は誤解。COW最適化を壊す場合あり
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/YJ6LKXLMEV.jpg)

③ 文字列のCOWとinterned string
$s1 = &quot;hello&quot;; // リテラルは interned string になり得る
$s2 = $s1;
xdebug_debug_zval(&#039;s1&#039;);
xdebug_debug_zval(&#039;s2&#039;);
$s2 .= &quot;!&quot;; // ★ここで分離
xdebug_debug_zval(&#039;s1&#039;);
xdebug_debug_zval(&#039;s2&#039;);
文字列も基本は COW
interned string は同じ文字列リテラルを一箇所にまとめて再利用する最適化を行
う。
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/GJ51PX1Q74.jpg)

まとめ
PHPの配列と文字列はCopy on Writeによって、書き込んだ瞬間にだけコピーされ
る。
参照（ &amp; ）はCOW無効化。乱用は逆効果になる可能性がある。
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/9E216X1WJR.jpg)

参考文献
PHP Manual: 変数の扱い / 参照 / GC Refcounting Basics
https://www.php.net/manual/ja/language.variables.basics.php
https://www.php.net/manual/ja/language.references.php
https://www.php.net/manual/en/features.gc.refcounting-basics.php
Derick Rethans: Xdebug 2.3: xdebug_debug_zval()
https://derickrethans.nl/xdebug-2.3-xdebug-debug-zval.html
PHP Internals Book（zval / Memory Management）
https://www.phpinternalsbook.com/
Qiita: tadsan
https://qiita.com/tadsan/items/0f7c20bdde119c9ce13e
12


