That's not technically correct with regards to PHP. Your statement that any changes to $arr1 or $arr2 only impact the one in question, however, is accurate. If no changes are made they still refer to the same data in memory. It's copy-on-write semantics.
$arr1 = [1,2,3];
// $arr1 is a pointer to a zval array [1,2,3] and refcount:1
$arr2 = $arr1;
// $arr1 and $arr2 are pointers to the same zval array but incremented refcount to 2.
$arr2[] = 4;
// at this point, $arr2 creates a new zval array, copies over the data from the first, sets the recount to 1, and appends int(4). The [1,2,3] array has its refcount decremented to 1 as it's still referenced by $arr1.
Actually that is outdated since at least PHP 7. In modern PHP the engine uses copy on write only for "larger" things, but "small" things like integers or booleans live on the stack and are copied around, avoiding heap allocations etc.
This isn't semantics, though, but implementation. As far as I'm aware there's no way to "observe" the copy short of digging into runtime debugging tools, so I think it's still fair to say the language has pass-by-value semantics. In C++ we still refer to things returned-by-value as returned by value despite the reality of NRVO, etc.
$arr1 = [1,2,3]; // $arr1 is a pointer to a zval array [1,2,3] and refcount:1
$arr2 = $arr1; // $arr1 and $arr2 are pointers to the same zval array but incremented refcount to 2.
$arr2[] = 4; // at this point, $arr2 creates a new zval array, copies over the data from the first, sets the recount to 1, and appends int(4). The [1,2,3] array has its refcount decremented to 1 as it's still referenced by $arr1.
[1] http://hengrui-li.blogspot.com/2011/08/php-copy-on-write-how...