Hello everyone, surely any of us already know about variables and references when learning the basics of programming when starting the profession. But when working with PHP some people seem to forget that it exists, or some people know it does but don’t know how to use it; Even a few of us have ever used it but have caused some unexpected errors.
To help you better understand variables and references in PHP, and also give me the opportunity to learn more about this feature, this feature, today I will write about the problem of referencing with variables in PHP. .
To ensure the accuracy of terms as well as definitions, in this article I would like to use some archetypal words compared to its definition:
Class
: ClassProperty
,properties
: Properties in the classObject
: data types are objects (can be objects or classes)Array
: the data type is an arrayReference
: reference
In this article, I define two functions that help me print out the value more easily:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // Dùng để log trên màn hình console function beatifyLog(...$arr) { foreach ($arr as $item) { print_r($item); } } // Dùng để log trên giao diện html function beatifyHtml(...$arr) { echo '<pre>'; foreach ($arr as $item) { print_r($item); } echo '</pre>'; } |
Reference variables
The variable $b
is now called the reference variable of $a
, also called (alias), when $b
and $a
point to the same memory address on the machine. At this point, $a
or $b
changes value, the other variable will also change.
1 2 3 | $a; $b = &$a; |
For example:
References in objects and arrays
In PHP, object variables are references, while arrays are not. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $arr = [ 'key' => 'value', 'other_key' => 'other_value', ]; $obj = (object) $arr; $arr2 = $arr; $obj2 = $obj; $arr['key'] = 'another_value'; $obj2->key = 'another_value'; beatifyLog('arr: ', $arr, 'arr2: ', $arr2); echo "=====n"; beatifyLog('obj: ', $obj, 'obj2: ', $obj2); |
The result is:
So how do we want the array to be referenced? I would like to share a useful foreach usage to help us get that:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $arr = [1, 2, 3, 4,]; beatifyLog('Initial Value: ', $arr); echo "=====n"; foreach ($arr as $item) { $item++; } beatifyLog('Foreach without reference: ', $arr); echo "=====n"; foreach ($arr as &$item) { $item++; } beatifyLog('Foreach with reference: ', $arr); |
And here is the result after running the above commands:
Reference in the function
PHP has support for variable reference when entering the function, the syntax:
1 2 3 | function fnName(&$a, $b) {} |
Here $a
is $a
reference variable, and $b
is a normal variable. Consider the following specific example:
1 2 3 4 5 6 7 8 9 10 11 12 | function test(&$a, $b) { $a++; $b++; } $a = 3; $b = 4; beatifyLog('Before: ', 'a=', $a, '; b=', $b); echo "n"; test($a, $b); beatifyLog('After: ', 'a=', $a, '; b=', $b); |
Result:
There are some problems with using reference variables
This is the part I look forward to most in this article. Below I would like to share the errors I have encountered and how to handle them when working with reference variable. Of course there will be a lot of cases missing, hope you can share more to help your article and other friends better understand.
Reference object
To talk about this issue, I would like to give a small problem to illustrate.
- For class
Date
with the methods as shown below1234567891011121314151617181920212223242526272829303132333435class Date{private $d = 0;private $m = 0;private $Y = 0;public function __construct(int $year, int $month, int $day){$this->Y = $year;$this->m = $month;$this->d = $day;}private function addSubZero(int $i): string{return $i > 9 ? $i : "0$i";}public function toString(): string{$Y = $this->Y;$m = $this->addSubZero($this->m);$d = $this->addSubZero($this->d);return "$Y-$m-$d";}public function addYears(int $num): Date{$this->Y += $num;return $this;}} - Given an array of random dates, for example12345678$db = ['2021-01-02','2020-01-02','2021-01-01','2020-01-05','2019-01-05'];
- Input a date (in the correct format), output values within 1 year of the date entered.Input example
2021-01-01
. The desired results with the arrays above are2020-01-02
,2021-01-01
and2020-01-05
.
** Below is my recommended code snippet:
1 2 3 4 5 6 7 8 9 10 11 12 | // Should be 2021-01-01 $curYear = new Date(2021, 1, 1); // Should be 2020-01-01 $prevYear = $curYear; $prevYear->addYears(-1); // Should return 2020-01-02, 2021-01-01 and 2020-01-05 beatifyLog('Result:', array_filter($db, function ($a) use ($curYear, $prevYear) { return $a >= $prevYear->toString() && $a <= $curYear->toString(); })); |
Test the code above:
See the results, not as expected, for details, I debug the above code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Should be 2021-01-01 $curYear = new Date(2021, 1, 1); beatifyLog('Initial CurYear: ' . $curYear->toString()); echo "n"; // Should be 2020-01-01 $prevYear = $curYear; $prevYear->addYears(-1); // Should return 2020-01-02, 2021-01-01 and 2020-01-05 beatifyLog('Result: ', array_filter($db, function ($a) use ($curYear, $prevYear) { return $a >= $prevYear->toString() && $a <= $curYear->toString(); })); echo "n"; beatifyLog('CurYear:', $curYear->toString()); echo "n"; beatifyLog('PrevYear:', $prevYear->toString()); |
Result:
So what is the reason? It is because of that object reference (I mentioned above).
Then is there a way to fix it? Of course yes, I try to use the clone
of PHP offline. Here is the code I have slightly modified:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | $db = [ '2021-01-02', '2020-01-02', '2021-01-01', '2020-01-05', '2019-01-05' ]; // Should be 2021-01-01 $curYear = new Date(2021, 1, 1); beatifyLog('Initial CurYear: ' . $curYear->toString()); echo "n"; // Should be 2020-01-01 $prevYear = clone $curYear; $prevYear->addYears(-1); // Should return 2020-01-02, 2021-01-01 and 2020-01-05 beatifyLog('Result: ', array_filter($db, function ($a) use ($curYear, $prevYear) { return $a >= $prevYear->toString() && $a <= $curYear->toString(); })); echo "n"; beatifyLog('CurYear:', $curYear->toString()); echo "n"; beatifyLog('PrevYear:', $prevYear->toString()); |
Here are the results:
The results are as expected !! You pay attention when manipulating objects in PHP.
Reference array
I would like to reuse a bit of the example in the reference section in the array, and at the same time edit a bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $arr = [1, 2, 3, 4,]; beatifyLog('Initial Value: ', $arr); echo "=====n"; foreach ($arr as &$item) { $item++; } beatifyLog('Foreach with reference: ', $arr); echo "=====n"; echo "Foreach without reference and do nothing.n"; foreach ($arr as $item) { } beatifyLog('And after that: ', $arr); |
And this is the result:
To explain this problem, it is probably advisable to go deep into the memory of the reference variable, so I would like to see you again next time. Here, I only propose a method to “avoid” it. Please see my rewrite as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $arr = [1, 2, 3, 4,]; beatifyLog('Initial Value: ', $arr); echo "=====n"; foreach ($arr as &$item) { $item++; } beatifyLog('Foreach with reference: ', $arr); echo "=====n"; echo "Foreach without reference and do nothing.n"; foreach ($arr as $itemOther) { } beatifyLog('And after that: ', $arr); |
Simply replace it with a different variable name, and here are the results:
Conclude
Above is what I have researched, and also gathered from some of my experience with references in PHP, hopefully somewhat useful for you in some cases.
Reference source
This article I mainly refer to on the PHP document page and the rest is due to the practical experience I have.