1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘】PHPのプリミティブ型・オブジェクト・配列での代入の挙動

1
Last updated at Posted at 2026-09-06

はじめに

PHPで変数を代入する場合に値の参照を渡すのか実体を新しく作るのか忘れてしまうことが多く、毎回動作確認をして試していました。
AIにコードを書いてもらう機会が増え、意識しないと見逃してしまいそうだなと思ったので、理解してまとめようと思います。

各操作における元変数の値の変化

プリミティブ型の場合

プリミティブ型は変数ごとに独立しています。
値を変更しても他の変数の値が変わることはありません。

別の変数に代入する場合
<?php

// 変数を作成し、別の変数に代入
$a = 'init';
$b = $a;

// それぞれ違う値に書き換える
$a = 'update_1';
$b = 'update_2';

// それぞれが書き換えた値になっていることを確認
echo 'a ===> ' . $a;
echo PHP_EOL;
echo 'b ===> ' . $b;
結果
a ===> update_1
b ===> update_2
更新する関数を呼び出す場合
<?php

function update($c)
{
    $c = 'update';
}

// 変数に値を代入し、更新する関数を呼び出す
$a = 'init';
update($a);

// 値は変わっていないことを確認
echo 'a ===> ' . $a;
echo PHP_EOL;
結果
a ===> init

影響させたい場合は参照渡しをする。

<?php

// 変数を作成し、別の変数に代入
$a = 'init';
$b = &$a; // ★参照渡し

// それぞれ違う値に書き換える
$a = 'update_1';
$b = 'update_2';

// どちらも同じ値になる
echo 'a ===> ' . $a;
echo PHP_EOL;
echo 'b ===> ' . $b;
結果
a ===> update_2
b ===> update_2
更新する関数を呼び出す場合
<?php

// 参照渡し
function update(&$c)
{
    $c = 'update';
}

$a = 'init';
update($a);

echo 'a ===> ' . $a;
echo PHP_EOL;
結果
a ===> update

オブジェクトの場合

オブジェクトの場合、値の変更をした場合は元の値にも影響があります

<?php

class Test
{
    protected string $name;
    protected int $price;

    public function __construct(){
        $this->name = 'init';
        $this->price = 0;
    }

    public function getName() { return $this->name; }
    public function getPrice() { return $this->price; }
    public function setName($name) { $this->name = $name; }
    public function setPrice($price) { $this->price = $price; }
}

// オブジェクトを作成し、新しい変数に代入
$a = new Test();
$b = $a;

// 代入元の変数と代入先の変数でそれぞれ値を更新
$a->setName('updateName');
$b->setPrice(1);

// どちらの変更でも両方の値が変更されていることを確認
echo 'a ===> name:' . $a->getName() . ', price: ' . $a->getPrice();
echo PHP_EOL;
echo 'b ===> name:' . $b->getName() . ', price: ' . $b->getPrice();

結果
a ===> name:updateName, price: 1
b ===> name:updateName, price: 1

関数内で更新する場合も同様です。

更新する関数を呼び出す場合
<?php

class Test
{
    protected string $name;
    protected int $price;

    public function __construct(){
        $this->name = 'init';
        $this->price = 0;
    }

    public function getName() { return $this->name; }
    public function getPrice() { return $this->price; }
    public function setName($name) { $this->name = $name; }
    public function setPrice($price) { $this->price = $price; }
}

function update($c)
{
    $c->setName('updateName');
    $c->setPrice(2);
}

// オブジェクトを作成
$a = new Test();

// 関数内でオブジェクトの値を更新
update($a);

// 関数内でされた更新で値が変わっている事を確認
echo 'a ===> name:' . $a->getName() . ', price: ' . $a->getPrice();
結果
a ===> name:updateName, price: 2

参照させたくない場合はcloneすることで別の実体を作成することができます。

cloneする場合
<?php

class Test
{
    protected string $name;
    protected int $price;

    public function __construct(){
        $this->name = 'init';
        $this->price = 0;
    }

    public function getName() { return $this->name; }
    public function getPrice() { return $this->price; }
    public function setName($name) { $this->name = $name; }
    public function setPrice($price) { $this->price = $price; }
}

// オブジェクトを作成し、新しい変数に代入
$a = new Test();
$b = clone($a); // ★cloneすると新しいオブジェクトになる

// 代入元の変数と代入先の変数でそれぞれ値を更新
$a->setName('updateName');
$b->setPrice(1);

// 変更がそれぞれのオブジェクトにしか影響していないことを確認
echo 'a ===> name:' . $a->getName() . ', price: ' . $a->getPrice();
echo PHP_EOL;
echo 'b ===> name:' . $b->getName() . ', price: ' . $b->getPrice();
結果
a ===> name:updateName, price: 0
b ===> name:init, price: 1

一方で、オブジェクトを保持するクラスをcloneしてもオブジェクト型のメンバ変数はcloneされません。

オブジェクト型のメンバ変数はクローンされない
<?php

class Test
{
    protected string $name;

    public function __construct(){
        $this->name = 'init';
    }

    public function getName() { return $this->name; }
    public function setName($name) { $this->name = $name; }

}

class ParentTest
{
    protected Test $test;

    public function __construct()
    {
        $this->test = new Test();
    }

    public function getTest() { return $this->test; }
    public function setTest($test) { $this->test = $test; }
}

// オブジェクトを作成し、新しい変数に代入
$a = new ParentTest();
$b = clone($a);

$a->getTest()->setName('update');

// 代入元の変数と代入先の変数でそれぞれ値を更新

echo 'a ===> name:' . $a->getTest()->getName();
echo PHP_EOL;
echo 'b ===> name:' . $b->getTest()->getName();
結果
a ===> name:update
b ===> name:update

その場合、__clone()にcloneされた時の操作を定義できます。

__clone()で$testもcloneする
<?php

class Test
{
    protected string $name;

    public function __construct(){
        $this->name = 'init';
    }

    public function getName() { return $this->name; }
    public function setName($name) { $this->name = $name; }

}

class ParentTest
{
    protected Test $test;

    public function __construct()
    {
        $this->test = new Test();
    }

    public function __clone()
    {
        // cloneされたら$testもcloneする
        $this->test = clone($this->test);
    }

    public function getTest() { return $this->test; }
    public function setTest($test) { $this->test = $test; }
}

// オブジェクトを作成し、新しい変数に代入
$a = new ParentTest();
$b = clone($a);

$a->getTest()->setName('update');

// 代入元の変数と代入先の変数でそれぞれ値を更新

echo 'a ===> name:' . $a->getTest()->getName();
echo PHP_EOL;
echo 'b ===> name:' . $b->getTest()->getName();
結果
a ===> name:update
b ===> name:init

配列の場合

配列自体は各変数で独立しています。
配列操作が別の配列に影響を及びすことはありません。

一方で、配列の要素については、各要素の型に従います。

配列の場合
<?php

class Test
{
    protected string $name;
    protected int $price;

    public function __construct(){
        $this->name = 'init';
        $this->price = 0;
    }

    public function getName() { return $this->name; }
    public function getPrice() { return $this->price; }
    public function setName($name) { $this->name = $name; }
    public function setPrice($price) { $this->price = $price; }
}

// 配列を作成し、別の変数に代入
$a = ['first', 0, new Test(), new Test()];
$b = $a;

// 代入元の変数と代入先の変数でそれぞれ値を更新
$a[0] = 'fffff';
$b[1] = 1;

// a[2] を別のオブジェクトに差し替えても $b には影響しない
$a[2] = new Test();
$a[2]->setName('aaaa');

// 代入前から存在するオブジェクトの場合、変更が代入先まで影響する
$a[3]->setName('bbbb');

// それぞれの結果を確認
echo 'a ===> 0:' . $a[0] . ', 1: ' . $a[1] . ', 2: ' . $a[2]->getName() . ', 3: ' . $a[3]->getName();
echo PHP_EOL;
echo 'b ===> 0:' . $b[0] . ', 1: ' . $b[1] . ', 2: ' . $b[2]->getName() . ', 3: ' . $b[3]->getName();
結果
a ===> 0:fffff, 1: 0, 2: aaaa, 3: bbbb
b ===> 0:first, 1: 1, 2: init, 3: bbbb

おわりに

今回は変数を代入した場合の動作を調べました。
AI時代こそこのような基礎を理解しておくのは非常に重要だと思います。
「試すのも面倒なのでよくわからないけどApprove」みたいなことをしないよう、これからも曖昧なところは理解していこうと思います。

ここまでご覧いただきありがとうございました!

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?