Ответ
Copy-on-Write (COW) — это внутренняя оптимизация в PHP, которая откладывает фактическое копирование данных (например, массива или строки) до момента, когда одна из переменных пытается изменить эти данные. Пока данные только читаются, несколько переменных могут ссылаться на одну и ту же область памяти, что экономит ресурсы.
Наглядный пример с массивом:
// Исходный массив занимает память X
$originalArray = [1, 2, 3, 4, 5];
// Присваивание. Копирования НЕТ.
// $copyArray и $originalArray ссылаются на одни и те же данные (zval).
$copyArray = $originalArray;
// Пока мы только читаем, память не дублируется.
echo $copyArray[0]; // Выводит: 1
// МОМЕНТ КОПИРОВАНИЯ (Write).
// Теперь, когда мы пытаемся изменить $copyArray,
// PHP создает физическую копию данных для $copyArray.
$copyArray[] = 6;
// Теперь $originalArray и $copyArray — это два независимых массива в памяти.
print_r($originalArray); // [1, 2, 3, 4, 5]
print_r($copyArray); // [1, 2, 3, 4, 5, 6]
Где это применяется и почему важно:
- Передача аргументов в функцию: При передаче массива в функцию по значению копия создается только если функция его модифицирует.
- Возврат из функции: Возвращаемый массив не копируется, пока вы не попытаетесь его изменить.
- Экономия памяти: В сценариях с большими массивами, которые часто присваиваются, но редко меняются, COW дает значительный выигрыш в производительности и потреблении памяти.
Важное отличие для объектов: Начиная с PHP 5, объекты по умолчанию передаются и присваиваются по ссылке на объект (object handle). Механизм COW к самим объектам не применяется, но может применяться к их внутренним свойствам-массивам.
Ответ 18+ 🔞
Давай разберём эту штуку, а то звучит как какая-то магия, а на деле всё просто, как три копейки.
Вот представь: у тебя есть здоровенный массив, ну, овердохуища данных. И тебе нужно его в другую переменную скопировать. Если бы PHP был тупым, как пробка, он бы тупо скопировал все данные, и память бы улетела в два раза. Ебать колотить, какой же он был бы тогда распиздяй.
Но он не такой. Он хитрожопый. Он использует Copy-on-Write (COW), что дословно значит «копирование при записи». Суть в чём? Пока ты данные только читаешь — копирования нихуя не происходит. Все переменные просто тихо, как мыши, смотрят на одну и ту же кучку данных в памяти. А вот в тот самый момент, когда какая-то из них возомнит себя главной и попытается эти данные изменить — вот тут-то PHP и говорит: «Ага, чувак, ты хочешь писать? Получай свою личную, отдельную копию, чтобы другим не мешать». И только тогда происходит настоящее копирование.
Смотри на примере, тут всё как на ладони:
// Создаём массив. Память занята под него.
$originalArray = [1, 2, 3, 4, 5];
// Присваиваем другой переменной. ВНИМАНИЕ!
// Копирования НЕТ. Вообще. Ноль.
// $copyArray и $originalArray — это как два парня, которые смотрят на одну и ту же бутылку водки.
$copyArray = $originalArray;
// Читаем. Всё ок, водку пока не трогаем, пьём из одной.
echo $copyArray[0]; // Выводит: 1
// А ВОТ ТЕПЕРЬ ПИЗДЕЦ (в хорошем смысле). МОМЕНТ ИСТИНЫ.
// Мы пытаемся ИЗМЕНИТЬ $copyArray. Добавить новый элемент.
// PHP резко просыпается: «Так, стоп, **ёпта**! Этот чувак хочет в эту водку свой огурец кинуть! Давайте ему его отдельную бутылку!»
// И ТОЛЬКО СЕЙЧАС происходит реальное копирование данных в памяти.
$copyArray[] = 6;
// Теперь у каждого своя буханочка. Независимые массивы.
print_r($originalArray); // [1, 2, 3, 4, 5] — оригинал нетронут, огурец не плавает.
print_r($copyArray); // [1, 2, 3, 4, 5, 6] — а тут уже полный ажур.
Зачем этот цирк? Да всё просто, я тебя умоляю.
- Экономия памяти, просто пиздец какая. Особенно когда у тебя мегабайтные массивы и ты их в десять функций передаёшь. Без COW память бы кончилась быстрее, чем терпение у тестировщика в пятницу вечером.
- Передача в функцию. Передал массив в функцию — и не парься, что он скопируется. Скопируется только если функция начнёт в нём ковыряться.
- Возврат из функции. Вернул массив — он не скопируется, пока ты его не модифицируешь.
НО! Важный нюанс, про который все забывают, а потом охуевают. С объектами в PHP (классами) — история другая. Начиная с пятой версии, объекты по умолчанию передаются и присваиваются по ссылке на объект (типа по хэндлу). Сам механизм COW к целому объекту не применяется. То есть, если ты скопируешь объект в другую переменную и поменяешь свойство — оно поменяется и в оригинале, потому что это один и тот же объект. Но! Если внутри объекта есть свойство-массив, то вот к этому внутреннему массиву COW уже может примениться. Вот такая, блядь, матрёшка получается.
Короче, хитрая жопа эта оптимизация, но полезная. Главное — понимать, в какой момент твои данные тихо раздваиваются, а когда они, как сиамские близнецы, живут одной жизнью.