Передаются ли аргументы в PHP по умолчанию по ссылке?

Ответ

Нет, по умолчанию аргументы передаются по значению. Это базовое поведение PHP для скалярных типов (int, string, bool, float) и массивов. Функция получает копию значения, и работа ведется с этой копией.

Демонстрация передачи по значению:

function tryToChange($array) {
    $array[] = 'new element';
    // $array теперь локальная копия, оригинальный массив не изменился
}

$myArray = [1, 2, 3];
tryToChange($myArray);
print_r($myArray); // Выведет Array ( [0] => 1 [1] => 2 [2] => 3 )

Чтобы передать аргумент по ссылке, нужно использовать оператор & в сигнатуре функции:

function actuallyChange(&$array) {
    $array[] = 'new element';
}

$myArray = [1, 2, 3];
actuallyChange($myArray);
print_r($myArray); // Выведет Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 'new element' )

Поведение объектов: Объекты передаются по ссылке по умолчанию (начиная с PHP 5). Хотя формально в функцию передается копия дескриптора объекта, эта копия указывает на тот же экземпляр в памяти, поэтому изменения свойств объекта внутри функции сохраняются.

$object = new stdClass();
$object->data = 'original';

function modify($obj) {
    $obj->data = 'modified'; // Меняет свойство исходного объекта
}

modify($object);
echo $object->data; // Выведет 'modified'

Ответ 18+ 🔞

А, ну это же классика, ёпта! Сидишь такой, пишешь код, думаешь — щас передам массив в функцию, там его поменяю, и всё будет огонь. А потом смотришь — а нихуя не поменялось! Вот тут-то и начинается волнение ебать, и терпения ноль ебать. Так вот, запомни раз и навсегда: по умолчанию всё идёт по значению. То есть функция получает свою собственную, отдельную копию твоего числа, строки или, что чаще всего бесит, массива. Работает с ней, а оригинал лежит себе нетронутый, как святой.

Вот смотри, как это выглядит на практике:

function tryToChange($array) {
    $array[] = 'new element';
    // $array теперь локальная копия, оригинальный массив не изменился
}

$myArray = [1, 2, 3];
tryToChange($myArray);
print_r($myArray); // Выведет Array ( [0] => 1 [1] => 2 [2] => 3 )

Видишь? Кинул ты массив, думал, что его там дополнят, а он вернулся первозданный. Чистая хитрая жопа, а не поведение. Сам от себя охуеешь, когда впервые с этим столкнёшься.

Но если тебе реально нужно, чтобы функция ковыряла именно твой исходный массив, то надо ей явно сказать. Ставишь перед аргументом в объявлении функции амперсанд & — это как пропуск "бейдж доступа" к оригиналу.

function actuallyChange(&$array) {
    $array[] = 'new element';
}

$myArray = [1, 2, 3];
actuallyChange($myArray);
print_r($myArray); // Выведет Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 'new element' )

Вот теперь работает. Функция получила не копию, а ссылку на ту же самую область памяти, где твой массив живёт, и спокойно в него записала.

А теперь про объекты — тут отдельная песня, ебать мои старые костыли. Начиная с пятой пыхи, объекты передаются по так называемой "ссылке на объект". Грубо говоря, ты передаёшь не весь объект (это было бы овердохуища данных), а его "пульт управления". И твоя функция, и ты снаружи — вы дергаете за одни и те же рычаги одного и того же экземпляра.

$object = new stdClass();
$object->data = 'original';

function modify($obj) {
    $obj->data = 'modified'; // Меняет свойство исходного объекта
}

modify($object);
echo $object->data; // Выведет 'modified'

Видишь? Без всяких амперсандов объект внутри функции изменился. Это потому что $obj — это не копия всего объекта, а ещё одна переменная, указывающая на того же самого "зверя" в памяти. Так что с объектами доверия ебать ноль — будь осторожен, они меняются везде.