PHPでの参照渡し

# **基本**

## **デフォルト値無しの場合**

関数定義で引数に **`&`** をつけると、関数内で扱う変数名が呼び出し元のスコープに存在する変数名の **エイリアス** のようになる。

```php:コード
<?php
function increment(&$var) {
    var_dump($var++);
}
$a = 1;
increment($a);
var_dump($a);
``` 

```text:結果
int(1)
int(2)
```

ここで、`increment()` に変数ではなく **値** を渡すと **Fatal Error** になり、スクリプト実行が停止される。

```php:コード
<?php
function increment(&$var) {
    var_dump($var++);
}
increment(1);
```

```text:結果
Fatal error:  Only variables can be passed by reference in ... on line 5
```

**代入式** を渡すと実行は可能ではあるが **Strict Standards** という旨のエラーが発生するので、可能な限りこう書くのは避けるべきである。

```php:コード
<?php
function increment(&$var) {
    var_dump($var++);
}
increment($a = 1);
var_dump($a);
```

```text:結果
Strict Standards:  Only variables should be passed by reference in ... on line 5
int(1)
int(2)
```

## **デフォルト値有りの場合**

関数への参照渡しには値渡し同様にデフォルト値を設けることが可能である。何も渡さなかった場合は値渡しの場合の挙動と差異は無い。

```php:コード
<?php
function increment(&$var = 5) {
    var_dump($var++);
}
increment();
``` 

```text:結果
5
```

PHPでは原則的に未定義の変数の値を取得しようとしたときに **Notice** が発生して **NULL** 扱いになるが、参照渡しのデフォルト値の場合だけ例外的に<ins>Noticeを発生せずに`NULL`として初期化される</ins>。この場合、<ins>関数側でデフォルト値に何を指定しても`NULL`と見なされる</ins>ことに注意する必要がある。

```php:コード
<?php
function increment(&$var = 5) {
    var_dump($var++);
}
increment($a);
var_dump($a);
``` 

```text:結果
NULL
int(1)
```

# **型による違い**

## **スカラー値・`NULL`・配列**

基本で述べたとおりで、特に言及点は無い。唯一気を付けることとすれば、 <ins>配列はオブジェクトでは無い</ins>ことが挙がるだろうか。他の言語出身者からすれば少し違和感のある定義であると思われる。

## **リソース**

リソースは自動的に連番で設定される **リソースID** によって管理されており、値渡しにしただけで感覚的には参照渡しのような扱いになる。しかし、関数内で変数に対して何か値を設定したところで、呼び出し元の変数に影響を与えるわけではない。あくまで<ins>リソースIDというスカラー値</ins>として考えると理解がしやすい。

```php:コード
<?php
function readline($fp) {
    echo "2: "; var_dump($fp);
    $line = rtrim(fgets($fp));
    $fp = null;
    echo "3: "; var_dump($fp);
    return $line;
}
$fp = fopen('test.txt', 'r');
echo "1: "; var_dump($fp);
echo "4: "; var_dump(readline($fp));
echo "5: "; var_dump($fp);
``` 

```text:結果の例
1: resource(1) of type(stream)
2: resource(1) of type(stream)
3: NULL
4: String(1) "a"
5: resource(1) of type(stream)
```

参照渡しにした場合は<ins>リソースID自体に参照がかかる</ins>として考えるといいだろう。

```php:コード
<?php
function readline(&$fp) {
    echo "2: "; var_dump($fp);
    $line = rtrim(fgets($fp));
    $fp = null;
    echo "3: "; var_dump($fp);
    return $line;
}
$fp = fopen('test.txt', 'r');
echo "1: "; var_dump($fp);
echo "4: "; var_dump(readline($fp));
echo "5: "; var_dump($fp);
``` 

```text:結果の例
1: resource(1) of type(stream)
2: resource(1) of type(stream)
3: NULL
4: String(1) "a"
5: NULL
```

## **オブジェクト**

オブジェクトもリソース同様に<ins>オブジェクトIDというスカラー値</ins>として考えると理解がしやすい。

```php:コード
<?php
function set_number_zero(stdClass $var) {
    $var->number = 0;
    echo "2: "; var_dump($var);
    $var = null;
    echo "3: "; var_dump($var);
}
$a = new stdClass;
echo "1: "; var_dump($a);
set_number_zero($a);
echo "4: "; var_dump($a);
``` 

```text:結果
1: object(stdClass)#1 (0) {
}
2: object(stdClass)#1 (1) {
  ["number"]=>
  int(0)
}
3: NULL
4: object(stdClass)#1 (1) {
  ["number"]=>
  int(0)
}
```

同様に、参照渡しにした場合は<ins>オブジェクトID自体に参照がかかる</ins>として考えるといい。

```php:コード
<?php
function set_number_zero(stdClass &$var) {
    $var->number = 0;
    echo "2: "; var_dump($var);
    $var = null;
    echo "3: "; var_dump($var);
}
$a = new stdClass;
echo "1: "; var_dump($a);
set_number_zero($a);
echo "4: "; var_dump($a);
``` 

```text:結果
1: object(stdClass)#1 (0) {
}
2: object(stdClass)#1 (1) {
  ["number"]=>
  int(0)
}
3: NULL
4: NULL
```

# **タイプヒンティングと`NULL`**

タイプヒンティングを用いる場合、デフォルト値として設定するものはそのタイプに合致するものでなければならないが、<ins>例外的に`NULL`だけは何に対しても設定が可能</ins>となる。

```php:コード
function dump_array(array $array = null) {
    var_dump($array);
}
dump_array();
```

```text:結果
NULL
```