Почему-то мои статьи в основном воспринимаются, как статьи для новичков, но, если что, я стараюсь писать для всех, и, более того, ориентируюсь больше на знающих людей, чем на новичков :). Поэтому не поддавайтесь заголовку: возможно, вы сможете найти для себя что-нибудь полезное.
В статье я хотел бы рассказать о некоторых прикольных моментах, с которыми может столкнуться разработчик на каком-нибудь динамическом языке, когда увидит PHP, или наоборот, разработчик на PHP, когда будет изучать какие-то другие динамические языки. Статические языки я не рассматриваю, ибо там вроде как всё итак понятно.
Причина, по которой я решил написать этот топик, проста: я бы хотел чуть-чуть просветить людей, которые не пишут на PHP (или очень мало писали на PHP) о некоторых интересных моментах в этом языке, о которых довольно-таки мало говорят. Я ни в коем случае не хочу никого убеждать, что PHP лучше, чем те же Python, Ruby, Javascript, [подставьте сюда свой любимый язык для веба]: более того, я так и не считаю. Мне просто «за державу обидно», когда на PHP наезжают, просто утверждая, без аргументов, что это плохой язык.
В качестве эталонного динамического языка я возьму JS, потому что, скорее всего, его все знают, кто пишет для веба. Ну а для тех, кто пишет на PHP и не знает JS, эта статья, наверное, может быть полезной в том плане, что она поможет лучше понять Javascript.
В PHP есть множество встроенных типов, и ни один из них не ведет себя, как объект. У встроенных типов нет свойств, методов и т.д. В этом плане PHP напоминает обычный C. Это играет роль, когда мы перейдем к следующему утверждению:
В PHP попытались возвести в абсолют концепцию языка С, что всё передается по значению. И они поначалу сделали это даже для объектов, но потом немного поменяли концепцию — объекты по-прежнему являются значениями, но это значение представляет из себя ссылку на инстанс класса.
Что это означает?
Давайте рассмотрим простой пример:
PHP:
Javascript:
Пример очень простой, но, ИМХО, довольно показательный. Давайте рассмотрим другой, как мне кажется, более прикольный, пример.
PHP:
Чувствуете :)? Замыкание по значению или по ссылке!
Javascript:
Респект тем, кто понимает, почему так происходит в JS, хоть это и канонический пример. А вот в PHP всё предсказуемо с точки зрения разработчиков на PHP, которые привыкли к тому, что всё передается по значению.
Во внутреннем устройстве PHP строки являются изменяемыми, поэтому операция "$var .= something;" в PHP — это нормально, и не создает никаких проблем с производительностью. В JS строки неизменяемые, поэтому писать «var += something» в большом цикле я бы не стал.
Также, в PHP есть отдельный оператор конкатенации: точка [.]. Простой пример:
В Javascript [ 3 + '3' ] это будет 33. Пичалька. Впрочем, в некоторых других динамических языках вам просто не дадут сложить строку и число без явного преобразования типов. Хорошо.
Вот об этом точно далеко не все знают. Если вкратце: хоть в PHP и всё передается по значению, но, на самом деле, копирование происходит далеко не всегда. Оно происходит, когда значение изменяется внутри конструкции, как, например, было в первом примере. Но это не единственный случай, когда создается копия. Подробнее об этом по ссылке.
Одним словом, эта оптимизация в PHP позволяет не терять производительность при передаче больших структур данных в функции, и вообще забыть о такой популярной вещи в jQuery, как $.extend().
Ну это, я считаю, позор для разработчиков JS: они бы точно могли бы добавить какое-нибудь, скажем, магическое, свойство length всем объектам…
В PHP полностью инвертированный подход к области видимости для функций, по сравнению с JS: любые глобальные переменные нужно явно объявлять, и все созданные переменные внутри функции по умолчанию локальны. Специально для новичков: не забывайте var в функциях JavaScript :).
Ну, в заключение, хотел бы передать привет Якубовичу, а заодно и Капитану Очевидности за помощь в написании этой статьи. Ну а если серьёзно, именно уникальная семантика PHP и встроенная поддержка огромного количества технологий позволяют лично мне до сих пор получать удовольствие от написания программ на PHP, даже несмотря на его очевидные минусы, вроде несогласованности названий функций, не самый краткий синтаксис, весьма низкую производительность и др.
В статье я хотел бы рассказать о некоторых прикольных моментах, с которыми может столкнуться разработчик на каком-нибудь динамическом языке, когда увидит PHP, или наоборот, разработчик на PHP, когда будет изучать какие-то другие динамические языки. Статические языки я не рассматриваю, ибо там вроде как всё итак понятно.
Автор, о чём топик-то? Кому вообще нужен твой PHP?
Причина, по которой я решил написать этот топик, проста: я бы хотел чуть-чуть просветить людей, которые не пишут на PHP (или очень мало писали на PHP) о некоторых интересных моментах в этом языке, о которых довольно-таки мало говорят. Я ни в коем случае не хочу никого убеждать, что PHP лучше, чем те же Python, Ruby, Javascript, [подставьте сюда свой любимый язык для веба]: более того, я так и не считаю. Мне просто «за державу обидно», когда на PHP наезжают, просто утверждая, без аргументов, что это плохой язык.
Интересные отличия PHP от Javascript
В качестве эталонного динамического языка я возьму JS, потому что, скорее всего, его все знают, кто пишет для веба. Ну а для тех, кто пишет на PHP и не знает JS, эта статья, наверное, может быть полезной в том плане, что она поможет лучше понять Javascript.
Всё, кроме объектов — значения
В PHP есть множество встроенных типов, и ни один из них не ведет себя, как объект. У встроенных типов нет свойств, методов и т.д. В этом плане PHP напоминает обычный C. Это играет роль, когда мы перейдем к следующему утверждению:
По умолчанию, всё передается по значению, и объекты тоже
В PHP попытались возвести в абсолют концепцию языка С, что всё передается по значению. И они поначалу сделали это даже для объектов, но потом немного поменяли концепцию — объекты по-прежнему являются значениями, но это значение представляет из себя ссылку на инстанс класса.
Что это означает?
Давайте рассмотрим простой пример:
PHP:
<?php
$arr = array(
'key1' => 'value1',
'key2' => 'value2',
);
function doSmthWithArray($arr) {
$arr['key3'] = 'value3';
}
doSmthWithArray($arr);
print_r($arr); // выведет "key1 => value1, key2 => value2" — исходный массив не изменился
Javascript:
var arr = {
key1: 'value1',
key2: 'value2'
};
function doSmthWithArray(arr) {
arr['key3'] = 'value3';
}
doSmthWithArray(arr);
console.log(arr); // выведет "key1 => value1, key2 => value2, key3 => value3" — т.к. в JS, по сути, нет встроенного типа «хеш», то это объект, и он передался по ссылке (впрочем, семантика передачи объектов — это отдельная тема. Конечно, просто сама по себе переменная представляет из себя ссылку на инстанс объекта, а не передача идет по ссылке, но это уже детали)
Пример очень простой, но, ИМХО, довольно показательный. Давайте рассмотрим другой, как мне кажется, более прикольный, пример.
PHP:
<?php
$funcs = array();
for($i = 0; $i < 10; $i++) $funcs[] = function() use($i) { return $i; };
foreach($funcs as $func) echo $func().",";
// выведется 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 !
$funcs = array();
for($i = 0; $i < 10; $i++) $funcs[] = function() use(&$i) { return $i; };
foreach($funcs as $func) echo $func().",";
// выведется 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
Чувствуете :)? Замыкание по значению или по ссылке!
Javascript:
var funcs = [];
for(var i = 0; i < 10; i++) funcs.push(function() { return i; });
for(var j = 0; j < funcs.length; j++) console.log(funcs[j]());
// выведется 10 раз по 10
Респект тем, кто понимает, почему так происходит в JS, хоть это и канонический пример. А вот в PHP всё предсказуемо с точки зрения разработчиков на PHP, которые привыкли к тому, что всё передается по значению.
Конкатенация строк
Во внутреннем устройстве PHP строки являются изменяемыми, поэтому операция "$var .= something;" в PHP — это нормально, и не создает никаких проблем с производительностью. В JS строки неизменяемые, поэтому писать «var += something» в большом цикле я бы не стал.
Также, в PHP есть отдельный оператор конкатенации: точка [.]. Простой пример:
<?php
$str = 3.'3'; // 33
$another_str = 3 + '3'; // 6
В Javascript [ 3 + '3' ] это будет 33. Пичалька. Впрочем, в некоторых других динамических языках вам просто не дадут сложить строку и число без явного преобразования типов. Хорошо.
Copy-on-write
Вот об этом точно далеко не все знают. Если вкратце: хоть в PHP и всё передается по значению, но, на самом деле, копирование происходит далеко не всегда. Оно происходит, когда значение изменяется внутри конструкции, как, например, было в первом примере. Но это не единственный случай, когда создается копия. Подробнее об этом по ссылке.
Одним словом, эта оптимизация в PHP позволяет не терять производительность при передаче больших структур данных в функции, и вообще забыть о такой популярной вещи в jQuery, как $.extend().
В PHP у хеш-массива можно легко узнать длину
Ну это, я считаю, позор для разработчиков JS: они бы точно могли бы добавить какое-нибудь, скажем, магическое, свойство length всем объектам…
По умолчанию, все переменные внутри функции в PHP локальны
В PHP полностью инвертированный подход к области видимости для функций, по сравнению с JS: любые глобальные переменные нужно явно объявлять, и все созданные переменные внутри функции по умолчанию локальны. Специально для новичков: не забывайте var в функциях JavaScript :).
Заключение
Ну, в заключение, хотел бы передать привет Якубовичу, а заодно и Капитану Очевидности за помощь в написании этой статьи. Ну а если серьёзно, именно уникальная семантика PHP и встроенная поддержка огромного количества технологий позволяют лично мне до сих пор получать удовольствие от написания программ на PHP, даже несмотря на его очевидные минусы, вроде несогласованности названий функций, не самый краткий синтаксис, весьма низкую производительность и др.