Pull to refresh

Comments 340

Указание типа для аргументов и trails радуют.
В тайп-хинтинге не будет неявного приведения типов. Т.е. '42' в int $a не передастся.

А если учесть, что у нас все данные снаружи приходят в строках — то весь код превратится в бесконечное явное приведение типов.

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

foobar($_POST['int']); — и вам придётся использовать (int) для приведения к целому.

Никто не заставляет, да, но почему было не сделать неявное приведение, как это сделано везде в пхп, а конкретно здесь идти по особому пути — лично мне непонятно
Думаю, что тогда и в таких конструкциях нужно будет задействовать преобразование:
public function test(Itest $test){}

Но я с вами согласен. Без приведения и правда становится грустнее.
возможно потому, что хотят сделать как в си, но утверждать точно не буду.
class bar {
function foo(int $a) {
}

function foo(array $a) {
}
}


но все же, иногда, строгая типизация бывает очень даже полезна.
С языках со статической типизацией — да, полезна. А делать из динамического языка — статический, только людей смешить. Как раз по тем причинам, что вместо программирования вы теперь будете сидеть и жонглировать явными приведениями
но ведь никто не заставляет это использовать повсеместно.
При этом для какого-нибудь Factory записи станут проще
Повсеместно — нет, но теперь как только вы захотите использовать какую-нибудь стороннюю библиотеку, которую писал вот такой «умник» — то привет

foobar((int) $a, (float) $b)
Раньше я писал
function foobar($id) {
$param = (int) $id;

}
foobar($_POST['id']);

теперь буду

function foobar(int $id) {

}
foobar((int)$_POST['id']);

Второй вариант, по-моему, более читаемый, что при объявлении функции, что при вызове. При объявлении не нужно приведения, и в обоих случаях сразу видно, что foobar ждёт число.
Раньше вы написали (int) раз и навсегда, а теперь все клиенты вашего метода обязаны его писать также.

Отлично просто стало.

Что foobar ожидает должно быть понятно из документации и подсказок IDE во время написания кода, и из имен переменных во время чтения.
class MyClass
{
    public function __construct()
   {
        $query = $this->registry
                               ->get_service('InputQueryBuilder')
                               ->get_query_object();

        $this->some_method($query->get('id', 'int')); // первый параметр - ключ, второй - ожидаемый тип
    }

    protected function some_method(int $id)
    {
        // тело метода
    }
}


Используйте инкапсуляцию запроса в объекте и будет вам счастье.
Я приницпиально не понимаю чем

$query->get('id', 'int')

лучше

(int)$query->get('id')

И ещё больше я не понимаю как ваш ответ решает необходимость указания типа везде вместо одного места раньше
$query->get('id', 'int') лучше, чем (int)$_POST['id']. Если вы не хотите везде указывать тип, то можно реализовать метод set_type($key, $type), который будет приводить значение ключа к типу и хранить его с этим типом в объекте запроса в дальнейшем. Тогда приведение нужно будет сделать только один раз, а если это не было сделано, то об этом подскажут сообщения о несоответствии типов.
>> $query->get('id', 'int') лучше, чем (int)$_POST['id'].

Чем? Вторая запись гарантирует итоговый тип аргумента, а первая — без просмотра реализации вообще непонятно что делает.

Перечитайте, пожалуйста, мой комментарий снова. Моя мысль была о том, что теперь вы в клиентском коде обязаны будете везде таскать нужные типы. А в случае изменения сигнатуры, опять же, по всей тонне клиентского кода бегать и менять вызовы.
Если вы имеете в виду ТОЛЬКО приведение к типу — то использование (int) безусловно нагляднее. Я же говорю о комплексной работе с запросом, раз уж ветка началась с идеи «все входящие параметры — строки, что делать дальше». Продолжим дальше на примере с id, полученным из браузера пользователя вместе с запросом:
use /Project/Validator/ValidatorI as V,
      /Project/Validator/Exceptions/ValidatorException;

// класс обладает знаниями о том, как выполняется определенное действие,
// запрошенное пользователем, и о том, какие типы и граничные значения
// имеют входящие параметры
class SomeActionController
{
    protected function validate_query(array $params)
    {
        try
        {
            // $params['id'] передается по ссылке 
            // и после валидации имеет заданный тип
            $this->validator->validate($params['id'], V::INT|V::UNSIGNED|V::NOT_NULL); 
        }
        catch (ValidatorException $e)
        {
            // обработка ошибки
        }

        $this->some_method($params['id']);
    }
}

В этом примере я пытаюсь показать, что если вы работаете в рамках фреймворка / CMS, то есть следующие особенности архитектуры:
1. Встроенный механизм комплексной проверки значений, с возможностью приведения к типу
2. Проверка значения и, соответственно, его типа происходит в одной точке и если проверка провалилась, то код сообщает об ошибке и прерывает исполнение. Далее используется уже проверенное и приведенное к типу значение, а не сырое значение из запроса
3. В модуле, который использует данные, имеются необходимые для проверки типа / границ допустимых значений знания
4. Переменная меняет свой тип в результате изменения логики работы модуля, а не наоборот
5. Соответственно, указание типа в сигнатуре должно применяться именно в тех случаях, когда от него зависит работоспособность кода, что хорошо демонстрирует пример с id, который всегда имеет тип integer, не может быть отрицательным, и обычно больше нуля
По всем пунктам согласен.

Однако используемый подход вы могли использовать и без тайп-хинтинга скалярных типов :-)

Итого: если вы пользовались тем, что вы описали — то для вас с появлением хинтов ничего не меняется. А если вы не пользовались этим всем — то введение хинтов на скаляры добавит головной боли.

Нет?
Безусловно да :) Но поскольку я считаю, что дисциплинировать программиста можно только тогда, когда код максимально строг, и за ошибки бьет по рукам, то хинтинг типов будет одним из способов заставить программистов, использующих мой код, пользоваться встроенными средствами валидации, а не бездумно пихать непроверенные данные в нижележащее ядро фреймворка. Вариация технофашизма, я бы сказал.
Может тогда на c# начать писать? :-)
Там о подобных ошибках вы бы узнавали ещё на этапе сборки проекта :-)

Ладно, не буду оффтопить, мы сошлись во мнении и это главное :-)
Никого не заставляю пользоваться своими методами :)

Нет документации и IDE ничего не подсказывает, она-то откуда знает число или строку я ожидаю в качестве id, если я не напишу function foobat(int $id). Есть, конечно, phpdoc, но меня его писать не заставляют. А насчёт имён — вводим венгерскую нотацию? nId вместо Id?
Не, не вводим. Имени должно быть достаточно ;-)

Но так или иначе — ваш «вариант 2» приводит к раздутому коду (для того, чтобы написать то же самое — клавиш нажать придётся больше)
Ну вот как может быть достаточно имени Id? Идентификатор может быть любого типа.

Очень многие способы «раздутия кода» улучшают читаемость и уменьшают количество возможных ошибок.
Уменьшают количество ошибок, совершенно верно.

Вы изменили сигнатуру метода в связи с переездом int $id на string $id.

Раньше для вас потребовалось бы изменить лишь тело метода (изменить принудительное кастование).

Теперь вам придётся по всем 100мб кода бегать и делать поиск-замену. Вероятность ошибки >> 0.
Сишники и явисты как-то же справляются, ещё и утверждают, что из-за статической типизации код у них надежнеё.
Потому что у них язык строго типизированный со статической типизацией. А пхп у нас слабо типизированный с динамической. И появление ущербной реалазиации тайп-хинтинга никак положение дел не изменит.

Равно как и не позволит появиться волшебным инструментам для рефакторинга и статического анализа, потому что язык по факту тот же самый, но с орешками.
UFO just landed and posted this here
Т.е. вы предлагаете делать класс-обёртку (см. костыль) только для того, чтобы потенциальный недостаток языка нивелировать. Правильно?

А веское основание — мы ушли от секвенций и решили использовать UUID.
UFO just landed and posted this here
>> В один прекрасный день мы обновляем бинарную библиотеку, и она начинает требовать других типов входящих параметров. Теперь вопрос: как заставить весь проект работать с новой библиотекой?

В том-то и дело: пхп язык с динамической слабой типизацией. В случае с пхп «раньше» — ничего страшного не произошло бы.

Не скатывайте дискуссию в кривую архитектуру, это всё софистика.

Ошибка разработчика — только теперь уже языка, а не приложения, в том, что сейчас в некоторых частях пхп неявное приведение будет, а в некоторых нет.
Это подарок в копилку несогласованных именований функций и порядка следования аргументов.
Неявное приведение было реализовано и так. Пишем $node_id=$id % $nodes_count и не обращаем внимание, что $id строка. И теперь мы можем его реализовать, просто не используй хинтинг. А вот если нам нужно явное приведение, мы его используем. Повторюсь, никто не заставляет вас использовать все возможности языка. Как никто не заставляет использовать библиотеки их использующие. В конце-концов, если библиотека свободная, то форкните её и удалите int в сигнатурах. Заодно сравните, какая большей популярностью будет пользоваться.
Популярностью всегда будет больше пользоваться библиотека от известного (см. оригинального) автора :-) Часто — вне зависимости от качества кода.

Т.е. ваша позиция: всё равно, что у языка часть вещей делается неявно, а часть явно?
Не всё равно, а хорошо. Там где я хочу чтоб делалось явно, я это декларирую, где не хочу полагаюсь на неявное.
UFO just landed and posted this here
Никто никого не заставляет, дело же добровольное! :)
И даже по всем 100Мб кода бегать никто не заставляет — есть шикарные функции рефакторинга в любой нормальной IDE и делается это на 30 секунд дольше чем «изменить лишь тело метода».
Плюсы вам привели — валидация значения внутри, а не извне.
Разработчики IDE могут применять более продвинутые алгоритмы code-completion.
Не сможете вы отрефакторить с гарантий безошибочности изменение типа в сигнатуре, потому что неизвестно когда приведение к этому типу осуществляется в клиентском коде.
Насчёт рефакторинга вы не совсем правы. Если используется «магия» типа $object->$method($id); то проблемы могут возникнуть, и IDE мало поможет, только тесты.
Почитайте Спольски, венгерская нотация должна использоваться не для указания типа переменной, а для указания какого-либо аспекта хранящихся в ней данных.
Я бы не стал так бесцеремонно передавать внешние данные напрямую в функцию, которая должна с ними работать. Скорее уж foobar( $request->get('int') ) или вообще foobar( $request ).
> но почему было не сделать неявное приведение

Ну, потому что это НЕ будет уже типизацией, а будет приведением типов, не более того… а это совсем другое.
Птому что явное приведение типов в неочевидных случаях — это правильно.
1. $object + 42
2. '42' + 42

В обоих случаях будет произведена попытка привести объект и строку соответственно в число. Это для вас очевидно?

А чем для вас приведение '42' как аргумента, объявленного как int — неочевидно?

Как раз в случае сигнатуры метода тип определён статически, а в арифметике — тип вообще в явном виде НИКАК не фигурирует.
Первый пример — должен падать с ошибкой.
Второй должен выполнять единственное очевидное действие, и преобразовывать 42 в строку, тем самым образуя '4242', хотя и это тоже можно поставить под сомнение, будучи особым пуристом.

Приведение '42' к инту для меня неочевидно потому, что если я так написал, значит я ошибся, и я хочу получить на это ошибку. Если я хочу преобразовать строку к числу, я буду использовать прямой метод преобразования, потому как можно выполнить такой преобразование десятком спобосов. Навскидку: '0x10' — ошибка или 16, '3000000000' — ошибка или unsigned, или bignum, или на флоат подменить, '1.0' — ошибка или 1, '01' — ошибка или 1, '-0' — ошибка или 0,.
Проблема в том, что второй пример сейчас в пхп работает. И ваше предложение превратить пхп в язык со строгой типизацией приводит к тому, что в некоторых местах пхп осуществляет неявное определение, а в некоторых — нет. Таким образом ведёт себя неконсистентно.

И наряду с разным стилем именования функций, разными порядками аргументов в схожих функциях у нас появляется ещё одна особенность, о которой нужно знать и постоянно помнить
Я не предлагаю ничего для ПХП. Вообще ничего. Для меня ПХП — богом забытый язык, на котором я, конечно, могу писать при сильной необходимости, но врядли выберу как язык решения какой-либо задачи, если не возникнет внешних ограничений(Стоит понимать, что «у меня тут апач с пхп, и мне надо хапустить прототип через час» — вполне себе ограничение, хотя в таком случае я все равно скорее всего выберу haXe.).
Вы не правильно понимаете назначение type hinting. Его нужно использовать ТОЛЬКО ТОГДА когда я ожидаю конкретный тип данных на входе, чтоб не писать лишних if. Потому и не происходит неявное приведение, потому что оно там быть НЕ ДОЛЖНО.
В ПХП данные из всех внешних источников приходят в строках.

Если вы работаете с внешними данными и у вас не строка — значит кто-то до вас это явное приведение всё таки сделал.
Т.е. взаимодействие слоев кода между собой вы не рассматриваете в принципе?
В слоях кода данные тоже появляются откуда-то.

Вы предлагаете только в части проекта использовать тайп-хинтинг?

Как вы тогда формализуете необходимость его использования в code conventions проекта? «Тогда когда нужно» — не является формальным определением.
В слоях кода данные появляются из внешнего кода, а во внешнем коде данные могут быть в любом виде.
Насчет формализации: а вы каждую фичу языка описываете в code conventions?
Type hinting подходит для библиотек или модулей напрямую не взаимодействующих с пользователем. Хотите — можете так и записать :)
Не каждую фичу, но для каждой специфичной конструкции языка должна быть описана применимость и способ записи. Иначе это не CC.

База — не пользователь, данные в строках.

Тогда может «напрямую не взаимодействующий с любым внешним источником»

Так или иначе — я вас понял. Через годик посмотрим, во что превратится код
Нормальные ORM преобразуют строки от PDO в PHP типы в соответствии с маппингом. Даже в объекты преобразуют, не то что в int или bool.

А вообще не нашёл я в ченжлогах scalar type-hinting. Только callable нововведение вижу.
Нормальные ORM и тапочки могут приносить.

В случае с «нормальными ORM» нам тайпхинтинг не нужен был и не нужен будет, потому что у нас данные и так гарантированно с нужным типом.
Вызов функции/метода может быть как с параметром от ORM, так и с другим. Мне проще писать функцию, где мне гарантированно приходит параметр с нужным типом, а не думать о том, стоит ли NULL приводить к 0 или выбрасывать исключение.
Справедливости ради нужно заметить, что не из всех. В качестве контрпримеров — данные из bound variables в PDO, данные из prepared statements в mysqli, данные из pecl/mongo, данные из DOMXPath::evaluate, результаты yaml_parse_url и т.п.
Они так же приходят в строках, а потом кастуются. Автоматически, но это ничего не меняет
Данные снаружи сначала нужно фильтровать. Поэтому приведение данных полученных извне к ожидаемым типам данных вполне нормальная практика имхо. Если мы ждем от пользователя целое число, а он нам передает и мы сразу же передаем это в функцию — это как бы не хорошо.
Я согласен с вами, что данные нужно валидировать, но не согласен с тем, что валидация как-то связана с приведением типов.

Если мы ждём от пользователя целое число — то мы можем применить ctype_digit() и не кастовать данные
Радуют все изменения. Особенно полная поддержка юникода.
Где вы увидели полную поддержку юникода? Её пока не сделали.
Одним из подтверждений будет, например, новая настройка в php.ini (http://cn2.php.net/ini.core.php) — zend.multibyte, которая по умолчанию установлена в false.

Кроме того можно посмотреть список багофиксов, в которых очень много изменений связано с юникодом и введением его поддержки. И хотя в официальном чендж листе нет фразы «Мы добавили юникод», можно с уверенностью сказать, что в 5.4 о в том или ином виде будет.
Под полной поддержкой юникода я бы ожидал увидеть его поддержку на уровне кода, а не только на уровне строковых литералов. Поддержка юникодных строк без его полной поддержки вероятнее всего даст просадку производительности.
Вот именно «в том или ином виде будет», а полной поддержки не будет.
Весьма интересно.
С массивами — казалось бы мелочь, но ведь так не хватало…
Честное слово, примеси в пхп — это какое-то недоразумение
Захотелось спросить на каком языке вы программируете :)
Отличный вброс, покормлю пожалуй.
я больше 5 лет программил на пхп
последние 2 года на питоне, немного руби, немного эрланг и жс на ноде
Да ладно, недавно делал систему поиска недвижимости, была куча типов недвижимости — строение, офис, квартира, участок и т.п., у каждого типа свой набор свойств, большинство из которых повторяется в большинстве объектов, но есть много уникальных. Чем хардкодить кучу подклассов или читать конфиги классов из файлов и динамически создавать в них свойства/методы — в разы легче, проще, удобнее, быстрее было бы сделать это с трейтами.
Я тоже недавно делал такую систему. Не вижу принципиальной разницы между наследованием и трейтами. use Common или extends Common… Другое дело, когда наследование нежелательно или невозможно, например все классы модели/контроллера уже наследуются от ActiveRecord или Controller или вообще не имеют общего в терминах предметной области, но вот чисто по коду имеют много общего, например реализация стандартных интерфейсов типа Iterator или ArrayAccess.
Порадовала короткая запись массивов.
Теперь удобнее будет передавать их в качестве аргументов в функции:
$obj->method([
'foo'=>'bar',
'bar'=>'foo'
]);

теперь это напоминает JavaScript ;)
Ага. Вроде мелочь, но выглядит значительно лучше.
Зачем? не лучше объявить

/**
@var int $foo
@var string $bar
**/
function method($foo, $bar)?
Ну, например, затем, чтобы делать внутри функции аналог джаваскриптовых пополнений объекта умолчаниями — таких, как $.extend(), _.extend(), _.defaults().
> в PHP 5.4 появится дополнительный источник мониторинга состояния загрузки.
> Он будет храниться в сессии пользователя в ключе, например, upload_progress_myform
Может ктонибудь пояснить как оно будет работать? У меня, например сессии в базе. Upload делается перед запуском скрипта, поэтому поставить свои обработчики сессии в скрипте, который принимает закачку, нельзя. Как же php сам сможет записать в сессию нужное значение?

И еще, раз сессия будет перезаписываться десятки раз во время закачки, значит здравствуй здоровенный io?
Встречный вопрос: для чего вы храните сессии в базе?

Почему я спрашиваю:
Если сравнить по скорости доступ к оперативной памяти, файлу на диске и базе то очевидно что самым быстрым будет доступ к памяти. Затем диск, затем база.

По умолчанию в пхп сессии хранятся на диске, т.е если бы мне хотелось ускорить что-то в этом и так быстром месте, то логичнее переместить сессии в memcache, но уж никак не в базу. Значит причина не в скорости.

Т.е у вас была причина пожертвовать скоростью ради… чего?
Звездец. Я разве об этом спросил?
А я и не отвечал на ваш вопрос, просто стало интересно зачем это может понадобится.
Например просто получить «сейчас на сайте хх человек»
Ну так для этого не обязательно хранить сессии в базе.
Ну хорошо если этот пример не нравится, то еще появляется возможность просто поправить данные одной сессии из другой.
И для этого база тоже не обязательна.
Тогда база и для хранения данных не обязательна, ведь можно использовать ФС вместо неё. А база не обязательно хранится на диске, можно дать таблице сессий тип memory, и иметь все преимущества скорости доступа к оперативной памяти и базы даннях храня сессии в базе.
Ну конкретно с memory могут быть проблемы — потому что там поле типа text создавать нельзя, а в сессии, бывает, СТОЛЬКО данных понапихают )))
Для плоских данных типа сессий — да. База не нужна. Поэтому и используют мемкеш или apc. Получается не база а key-value хранилище.

В случае если мы используем тип таблиц memory все ок, но все еще не видно очевидного профита.
Т.е программист написал хендлеры для базы, сделал таблицы особенного типа. Т.е потратил на это время. Он очевидно должен был получить какой-то очень полезный бонус в замен. Вот я спрашиваю — что это за бонус?
Доступ к сессиям извне, простое изменение данных всех сессий из php.
load balancing + REST. Пнрвый запрос пришел на один сервер, второй — на другой. Как восстанавливать контекст пользователя?
биндить юзера (сессию) к одной ноде например :)
Все равно поиск в базе будет происходить. И что будем делать, когда у нас пришли все юзеры именно этой ноды? ;)
а что мы будем в базе искать, то? Пришли и пришли, что с того?
> а что мы будем в базе искать, то?

Каким образом будет происходить следующее:
биндить юзера (сессию) к одной ноде например :)

?

Маленькими гномиками и магией?

> Пришли и пришли, что с того?

Клиентов всегда больше, чем серверов. Обычно намного больше. Если ты жестко привязываешь пользователя к ровно одному узлу — добро пожаловать в DoS в случае, если на эту ноду внезапно придут большинство пользователей, привязанных к этой ноде.
Жестко пользователей привязывать это перебор, конечно, но вот открываемую сессию к наименее нагруженной ноде (реальной нагрузке или по числу обслуживаемых сессий), по-моему, в большинстве случаев должно хватить без необходимости расшаривать данные сессии между нодами
ИМХО, кросдоменная авторизация… Работал давненько в одной конторе, где была куча проектов на поддоменах и для того чтобы сеесия оставалась неизменной с ней работали через БД.
З.Ы. Придумывал такой вариант не я, я только привел пример!
Ну например, стоит использовать базу данных для хранения сессий в том случае, если у вас количество серверов, которые обрабатывают запросы пользователей, больше одного. В этом случае вам файловая система и тем более APC не подходят. Memcached же не подходит по той причине, что данные сессий старых пользователей могут быть вытеснены новыми данными. Вам же, например, не очень приятно, когда вы заходите на какой-нибудь сайт каждый день, а он постоянно просит вводить у вас логин и пароль и не запоминает авторизацию. Это же плохой user-experience.
Именно поэтому имеет смысл сохранять данные сессии в персистентное внешнее хранилище данные, которое может быть и MySQL-ем, и Redis-ом или вообще каким-нибудь Membase-ом.
> Вам же, например, не очень приятно, когда вы заходите на какой-нибудь сайт каждый день, а он постоянно просит вводить у вас логин и пароль и не запоминает авторизацию.

Это уже куки, а не сессия.
На всякий случай расскажу как работают сессии в PHP:
Когда вы начинаете работать с сессионными данными для подключения, php задает куку с именем, который вы указываете в конфиге (по умолчанию PHPSESSIOID вроде) и уникальным значением, которое хранит в себе ID сессии пользователя. При каждом запросе к скрипту идет выборка этой куки и поиска сессионных данных, что соответствуют этой куке. Если сессионных данных не будет найдено, например, по причине того, что они хранились в APC, а вы перезапускали свой апач, то соответсвенно и слетит авторизация.
Тогда и я на всякий случай напомню Вам как работают сессии в PHP.

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

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

Конечно, плохо, если сессия «поломается» при простом сёрфинге по сайту, но надо так рассчитывать нагрузку и объём, который будет в сессии храниться.
Да, вы правы. Приношу извинения, не стоило мне отвечать в таком тоне. :-)
Действительно, спасибо, будем знать.
Про ввод паролей вы плохой пример привели — никто не реализовывает вечноживущие сессии для этого, а просто поднимают новую с уже известным user_id. По остальным доводам — да, +1
Не совсем понял механизм, что вы предлагаете для вечноживущих сессий.
В любом случае, нужно хранить куку в какой-то базе данных, которая связана с профилем пользователя, по которой и проводится аутентификация.
Я как раз предлагаю никогда не использовать вечноживущие сессии вообще.
А в куке просто лежит рандомный идентификатор который где-то в хранилище однозначно связывает нас с user_id.

Если при первом запросе пользователь не аутентифицирован, аутентификационная кука существует и присутствует в базе — тогда поднимаем свежую сессию и пишем туда уже известный user_id

Повторю: это не вечноживущие сессии, сессии в этом случае живут сколько и должны жить :-)
Ага, понял вас. По всей видимости мы немного по разному интерпретировали понятие сессии. Я имел ввиду не те данные, что хранятся в $_SESSION, а немного более широкое понятие.
А так да, конечно, стоит разделять данные, которые должны храниться для пользователя максимальное количество времени и данные, которые необходимо знать только в рамках текущей сессии (простите за тавтологию :-) ). К этим данным разные требования и, соответственно, разный механизм работы с ними.
Мммм, а откуда user_id становится заранее известным?
Из отдельной куки, являющейся ключом к таблице (или ещё какого хранилища), где есть user_id
То есть предлагаете городить огород вместе вечноживущих сессий? А зачем?
А зачем вам вечноживущие сессии? Не стреляйте из пушки по воробьям.

Задача: уметь производить аутентификацию пользователя через неделю.

Решение с отдельным хранилищем: узкоспециализированное, решает конкретно эту задачу.

Решение с вечноживущими сессиями: вместе с необходимыми данными также сохранит кучу потенциально ненужного мусора.
Мне надоело спорить уже, кстати. Сдаюсь везде, где не был прав на 100% ))
Я только хотел узнать: какого мусора?
В сессиях часто хранятся значения, которые имеют смысл только «здесь и сейчас». Это и есть мусор
Задам, возможно, крамольный вопрос: что мешает удалять значения из сессии, когда здесь и сейчас закончилось?
А откуда мы знаем, когда оно закончилось? К примеру — время жизни неких данных == пользовательский сеанс работы (равный времени среднестатистической сессии).

Пример данных: кэш каких-то не очень важных данных.

Как мы узнаем, когда удалять их? Положили в сессию, сессия протухла, PROFIT
Стоп. Вы не обижайтесь, но кэш, хранящийся в сессии, пахнет сливами.
Окей, это не кэш, это список посещённых в этой сессии страниц
Не вижу абсолютно никаких проблем в вечно хранящемся списке посещенных страниц (еще желательно с таймстампами и прочими полезными данными). Думаю, разработчики поисковых гигантов и рекламных систем меня поддержат.
В вечно хранящемся списке где? В вечно живущей сессии?
Или в базе?

Следующий кандидат — csrf токен. Слишком долго живущим делать нельзя, сессионный ttl — как раз окей.
Но для этого (как и для кэша) должно быть реализовано отдельное специализированное хранилище.

В сессии хранятся (должны хранится) как раз те данные, которые не потеряют актуальность, даже если пользователь впал в кому или на телефоне закончились деньги. Например, адрес, который пользователь ввел в форму заказа, а потом решил нажать назад, чтобы посмотреть что-нибудь еще. Или идентификатор самого пользователя. Или личные предпочтения (но вообще для них тоже должно быть создано более идеальное хранилище).
Кому «должны»? В сессии могут храниться любые данные, которые мы хотим.

Первые шаги длинной формы, в начале которой пользователь вводил данные от сторонних ресурсов и которые устаревают через некоторое время.

Зачем сохранять их перманентно? Не нужны они нам перманентно
Никому они не нужны. У вас по обсуждаемой теме есть что ещё сказать, или вы перешли на стратегию «и чо?»?
Ох. Я вам говорю — каждому-свое, и в сессии не должно быть кэша, а вы мне отвечаете: ну, «нам» нужно обязательно запихнуть в сессию «данные, которые могут протухнуть» (хотя это и есть вольное определение слова «кэш») и гнете таким образом свою линию. Ок, продолжайте.
Ок, расскажите, зачем нам нужны сессии длиной в год.

Вы же предпочитаете специализированные хранилища для каждой задачи, как вы выше сказали — давайте тогда от этого и отталкиваться.
Не в год, а в вечность, хе-хе:)
Ну поймите же, у сессии в идеале вообще не должно быть экспайра. Экспайр может быть у кэша (хотя и там он совсем не обязателен, по крайней мере в идеале для кэша лайфтайм должен быть по умолчанию тоже вечностью, если явно не указано другое), но поскольку у нас нет квантовых хранилищ информации, нужно как то стирать случайных посетителей. В то же время, если человек выбирает «ЗАПОМНИТЬ меня», приборчик обязан его, черт побери, запоминать! В самом деле, вы же за забудете человека, если один раз запомните его? А веб-сайты это постоянно делают, сплошная ложь кругом.
Вы всё таки не ответили — зачем бесконечные сессии?

«В идеале» — не аргумент.

>> в идеале для кэша лайфтайм должен быть по умолчанию тоже вечностью
Тогда ресурсы будут тратиться на инвалидацию.

>> В то же время, если человек выбирает «ЗАПОМНИТЬ меня», приборчик обязан его, черт побери, запоминать!
Должен. Посмотрите выше — вы за «специализированные» персистентные хранилища под каждую задачу. Сессия — не специализированное и не персистентное. Если человек потеряет сессионную куку (или пересядет за другой браузер) — тогда данные потеряются.
Я отвечу еще раз не зачем, а почему. Потому что в хранящихся ограниченное время сессиях есть небольшая проблема. Дело в том, что разные данные имеют тенденцию протухать с разной скоростью, так что например приведенный вами пример длинной формы может храниться несколько дней, а упомянутый опять же вами токен csrf может испортиться и через несколько секунд. Приводить весь этот огород к одному универсальному числу не имеет никакого смысла.

К тому же, в вечных сессиях очень прикольно хранить такие штуки, как все ай пи адреса, с которых заходил пользователь, или еще какие-то данные, которые должны быть спрятаны от всех, включая разработчиков, и доступны только для какого-либо анализа.
>> К тому же, в вечных сессиях очень прикольно хранить такие штуки, как все ай пи адреса, с которых заходил пользователь
Создайте «специализированное хранилище» и храните это там. Какой смысл хранить данные в месте, где их аналитика затруднена?

user_id | ip | date — вот вам таблица, кладите туда и будет вам счастье. И будет вам вся мощь sql доступна, безо всяких трюков.

Т.е. вы так и не привели доводов «за» долгую сессию :-)
>> которые должны быть спрятаны от всех, включая разработчиков
Вопросы безопасности и доступа вообще сессиями никак не решаются. Если разработчик имеет доступ к базе, то и к сессиям он получить доступ сможет.

Более того, если сессии у вас хранятся в чём-то экзотическом — то забудьте о всяких прикольных штуках и анализе.
Бывают такие куки, которые сложно потерять. Да и синхронизация не такая большая проблема в вероятном будущем. Касаемо ресурсов, то это проблему можно решить отдельным камнем на ssd-диске, которые будет заниматься только инвалидацией. Ну, знаете там, хранить карту, следить за atime и size, вот это все.
>> которые будет заниматься только инвалидацией.
Инвалидация это ещё и логика, хранение дерева зависимостей и прочее. Зачем — если вариант с ttl 15 минут решает проблему?

Куки по определению потереть легко, любые.

>> Ну, знаете там, хранить карту, следить за atime и size, вот это все.
зачем писать отдельную логику, если всё уже придумано и реализовано?
Пока отдельного камня нет, я за кэш прямо сейчас скажу вот что: если его просто дропать в нужные моменты, и хранить с ассоциативным графом при этом, и не хранить в кэше вечно то, что может засорить в будущем диск — с современными объемами хардов проблема не такая уж и большая. Я, во всяком случае, пока отлично обхожусь без инвалидации.
>> если его просто дропать в нужные моменты
Этот процесс и называется «инвалидация». Просто вы, судя по всему, инвалидируете весь кэш (o_O), а не конкретные элементы.

Да и кэш на харде, медленном ресурсе… :-S
Насколько медленном? У вас скорость интернета внезапно превысила 6 гигабит/сек?
Вы издеваетесь? Время случайного доступа у памяти и HDD сравните, угу?
Э. Вообще-то у SSD дисков (во всяком случае, мне такой экземпляр наверное попался) время случайного и последовательного доступа никак друг от друга не отличаются. RAID контролеры тоже частично снимают эту проблему. Допускаю, что в целом время доступа к памяти и к контролеру SATA могут отличаться в пользу памяти, но не думаю, что разница настолько огромная, чтобы на нее так дрочить. Ну и эцсамое, жрите поменьше, кэш магазина на 1000 товаров занимает… ну, гигабайта два наверное.

Кстати, такая инвалидация происходит ведь при изменении данных, это случается в десятки раз реже, чем просмотр. Что касается о_О, то вы пропустили мой пассаж про ассоциативное дерево, а теперь чему-то удивляетесь.
Да, я удивляюсь, что вместо автоматической инвалидации по TTL вы поддерживаете деревья связей и реализуете это вручную.

По-прежнему, это никак к вечно живущим сессиям не относится
Ну и заодно — модели HDD, которые умеют 6гбит
Смею также заметить, что вы до сих пор ни одного довода за бесконечные сессии не привели.
Да это потому что я комментировать только раз в пять минут умею.

Суть токова.

Чтобы закончить с инвалидацией — зря удивляетесь, потому что это не инвалидация на самом деле (как считаете вы) а именно дропание. Инвалидация, это когда на место дропнутого кэша генерируется новый, а на этот случай дерево блоков как раз и позволяет сэкономить ресурсы и не генерировать новые блоки того, что не изменилось. А вручную, это как-то так: cache::drop('catalog') или cache::drop_by_tag('product_1').

Насчет вечноживущих сессий я честно не знаю, чего вы добиваетесь, ведь я же уже несколько раз сказал: данные, которые нельзя светить в бд/где угодно, где их можно легко найти, но нужно хранить и использовать. Пример, кстати, вы привели сами в самом начале: идентификатор текущего пользователя. Аргумент: пользователь, кем бы он ни был, не должен знать своего идентификатора. Тем более иметь возможность подменить его в куке.
>> данные, которые нельзя светить в бд/где угодно, где их можно легко найти, но нужно хранить и использовать.
Эм, сессии — не способ обеспечить безопасность и сохранность данных вашего приложения. «где угодно» — это хранилище для сессий.
Мимо кассы.

>> Аргумент: пользователь, кем бы он ни был, не должен знать своего идентификатора. Тем более иметь возможность подменить его в куке.
Я и не говорил, что в куках будет id пользователя.
Как раз сессии идеальное место, если они хранятся внутри криптоконтейнера. Вечно.

> Я и не говорил, что в куках будет id пользователя.
Бритва?
Если они хранятся в контейнере и их может расшифровать вебсервер — то их может прочитать любой, у кого есть доступ к вебсерверу. Равно как и из базы может прочитать тот, у кого ест ьдоступ к базе.

Про бритву не понял

habrahabr.ru/blogs/php/136800/#comment_4553759
Ну вы советуете завести под id пользователя видимо какое-то отдельное хранилище. Я говорю, что это Бритва Оккама, и давайте же в это хранилище и остальные данные пихать, и назовем его сессия, и не будем его экспайрить.
Мне из этого отдельного хранилища нужно только одно значение, user_id

Ради одного значения менять хранилище — смысл?
Не, не так, это вам нужно хранилище только для одного значения. Вот я и спрашиваю, какой смысл создавать такое хранилище?
Погодите — это же ваша мысль, что нужно каждую задачу решать конкретным хранилищем. Например — это вы предложили принципиально кэш всегда храниться в кэше, просто потому что он кэш.
Вот и здесь та же петрушка — конкретная задача, конкретное решение.

Или вы посередине дискуссии меняете свою позицию?

Если будете продолжать настаивать на «всё в кучу» — тогда я предлагаю довести до крайности и в принципе создать в базе одну таблицу и хранить в ней всё, денормализованно.
Не каждую, не думайте за меня плиз. Кроме того, я считаю, что сессия и есть идеальное хранилище для идентификатора пользователя.

2VolCh: Пользователь не должен знать ничего о том, как он представлен внутри системы управления сайтом, в том числе не должен знать свой айди. Для меня это настолько очевидно, что я даже не знаю, как это понятно аргументировать. Ну, например, это уже осложняет некоторые SQL-инъекции как минимум.
Ну вот я знаю свой id на хабре (не суррогатный в виде PK в БД, а настоящий идентификатор). И вы знаете. Чем это плохо? Для меня совсем не очевидно.

Вводя суррогатный числовой ключ для идентификации (не авторизации) я лишь исхожу из «предположения», что сравнение и связи по строкам более медлительны, чем по целым числам и что (в меньшей степени) стоки занимают больше памяти. То есть просто внутренняя оптимизация потребляемых ресурсов, а не создание дополнительного уровня безопасности.

А SQL инъекции я стараюсь полностью исключить, а не осложнять их — если злоумышленник смог выполнить выборку из БД, то знание моего настоящего id или суррогатного ему мало жизнь осложнит. Или вы рекомендуете, например, таблицу users называть afdsfhkuitdafvnltjhgiltuj (про возможность получить схему данных вообще молчу)?
>А SQL инъекции я стараюсь полностью исключить
Ну-ну. Читали Мюнхгаузена? «Броня, которую не может пробить ни один снаряд. Снаряд, который может пробить любую броню.» Так и живем.
>сессия и есть идеальное хранилище для идентификатора пользователя.

OMG. Я зайду с другого компа/оси/учётки/браузера или даже с той же их комбинации, но место для кук закончится (не проверял в современных браузерах, но для 3-го фокса, например, их общее количество ограничено несколькими тысячами) или случайно сотру куки и не смогу воспользоваться своим ид, зарегистрированным в другой «вечной» сессии? Может, всё-таки, вы храните ид пользователя в более надежном хранилище, а в сессии лишь кэшируете результат аутентификации? Иначе надеюсь, что вашими сайтами мне пользоваться не придётся.
>Аргумент: пользователь, кем бы он ни был, не должен знать своего идентификатора. Тем более иметь возможность подменить его в куке.

Почему не должен? Он не должен иметь возможности представиться другим, а знать свой. Да даже если его другие знают… Чем это плохо?

А по сути механизм сессий в PHP вовсе не предназначен для хранения секретных данных. Он предназначен для передачи данных между двумя запросами, чтобы не передавать их постоянно от сервера к клиенту и обратно в урле, полях форм или куках, а передавать лишь ключ в каком-то key-values хранилище. Более того в описании механизма сессий явно указывается, что он не предполагает и не гарантирует, что информация доступна только пользователю-владельцу сессии.
Смотрю, к разговору совсем наркоманы подключаются. Результат аутентификации и есть идентификатор пользователя, а вы занимаете совершенно бессмысленными с точки зрения информационной безопасности экстраполяциями.
Результатом аутентификации является булево значение, что предъявленный идентификатор (логин) и его характеристика (пароль) соответствует друг другу. Всё. Какие-то дальнейшие действия типа получения из БД и сохранения в сессии суррогатного ключа пользователя — это уже действия с аутентифицированным пользователем, после того как получен положительный результат аутентификации.

Насчёт наркомана слова над не возьмёте?
Стало быть, в сессии все-таки?

Что-что мне со словами сделать?;)
В сессии, может быть, хранится кэш запросов из БД — это оптимизация, не более. К безопасности никакого отношения это не имеет, если её не ослабляет вообще (за счёт лишнего звена). А сами идентификаторы пользователей хранятся в БД (или каком другом хранилище).

*назад
Еще один. Дайте угадаю: у вас кэш хранится в сессии, а сессия хранится в кэше (например, в мемкэше)? Такое яйцо горыныча прямо.
Только не Горыныча, а Кащея.

А вы таким подходом не пользуетесь? Не храните одни и те же данные в кэшах L1/L2/L3 процессора, внутреннем кэше диска, в дисковом кэше ОС, кэше СУБД и кэше приложения? Насильно отключаете все кроме одного? Какого и как, не поделитесь? На уровне PHP конечно, а не ассемблера, прошивок и патчей ядра.

Это не говоря о том, что memcache называть кэшем несколько некорректно. Это инструмент для организации высокоуровневых разделяемых кэшей и, да, иногда я храню данные сессий в нём.

В общем сложилось впечатление, что вы используете best praсtices без понимания что именно вы делаете. Может нашли их в интернетах, может дошли методом проб и ошибок, выявив узкие места профайлингом или ещё чем, может интуиция или анализ задачи в целом подсказали, но понимания этапов решения задачи типа «пользователь не должен на каждой странице вводить логин и пароль, а приложение должно иметь возможность быстро получить связанные с ним данные» не видно.

Хотя, может, это я тупой и не могу представить себе задач для которых не нужно хранить идентификаторы пользователей в СУБД, файлах или ещё каком постоянном хранилище, чтобы пользователей мог получить к ним доступ с любого компа/ос/браузера/учётки, а достаточно только сессий. Или даже не достаточно, а необходимо, чтобы пользователь после переустановки ОС или очистки кук не мог получить доступа к своим данным. В таком случае не расширите ли мой кругозор, не подскажете пример такой задачи?
> Хотя, может, это я тупой и не могу представить себе задач для которых не нужно хранить идентификаторы пользователей в СУБД, файлах или ещё каком постоянном хранилище, чтобы пользователей мог получить к ним доступ с любого компа/ос/браузера/учётки, а достаточно только сессий.
Чувак, я ничего не понял, но ты достучался до моего похуй.

> В общем сложилось впечатление, что вы используете best praсtices без понимания что именно вы делаете.
Замечательно. У меня от вас именно такое же впечатление осталось, причем с самого начала разговора. По крайней мере вы свой вывод сделали только на основании того, что я, по вашему, слушком плохо веду демагогию, в отличие от.
>Чувак, я ничего не понял,

На пальцах — идентификаторы пользователей должны храниться в базе, хотя бы для того, чтобы пользователь мог залогиниться с любого компа и его суррогатный идентификатор мог быть скопирован из базы в новую сессию. Хранить идентификаторы в сессии, то есть заставлять пользователя регистрироваться заново при смене окружения и/или потери «вечной» сессионной куки — жестоко.

>По крайней мере вы свой вывод сделали только на основании того, что я, по вашему, слушком плохо веду демагогию

Нет, на основании фраз типа «Результат аутентификации и есть идентификатор пользователя», ведь идентификатор (логин) предъявляется пользователем вместе с другой характеристикой (паролем), результат проверки соответствия которых и будет результатом аутентификация. Соответствует пароль логину или нет, третьего не дано (если не считать ошибок выполнения) — результат булев — да, соответствует, или нет, не соответствует, пользователь тот, за кого пытается себя выдать или нет, true или false. Всё остальное (типа вытаскивания числового id из таблицы users по текстовым логину и паролю и сохранения его в сессии) — это оптимизации как UI (чтобы не заставлять пользователя при каждом запросе вводить логин и пароль), так и ресурсов (чтобы не дергать при каждом запросе базу, проверяя логин и пароль, и не связывать таблицу users с другими по текстовому логину) с безопасностью (чтоб не хранить пароль, пускай и хэшированный с солью, в куках или той же сессии). Вы же называете это всё одним процессом — аутентифкацией, хотя тут заключено ещё минимум 3 процесса оптимизации: UI и безопасности — пользователь передаёт логин и пароль только один раз, а дальше только идентификатор сессии посылает, ресурсов и безопасности — кэширование результатов запроса на соответствие логина и пароля (htcehcs), и, как следствие, ненужность хранения пароля в сессии (безопасность), и ещё раз ресурсов и безопасности — связь таблицы users осуществляется с другими по суррогатному числовому идентификатору, а не по натуральному текстовому (логину), связь по такому id быстрее (ресурсы) и отсутсвие необходимости хранить натуральный текстовый в сессии безопаснее немного. Плюс микрооптимизация в виде проверки результата аутентификации через isset($_SESSION['user_id']), а не $_SESSION['user_is_authenticated'].

Если и такое объяснение непонятно, то я умываю руки.
Дружище, у меня поле в таблице называется user_id, а не user_surrogate_id, думаю, у тебя так же, так о чем ты пытаешься спорить? Я обожаю эту тенденцию на хабре, додумать за меня то, что я не говорил, причем додумать каким-то идиотским образом, потом на основании додуманного назвать меня идиотом и на сотню-другую комментов доказывать мне это. God Bless America!
Результат аутентификации и есть идентификатор пользователя — разве я это сказал? Или это я додумал?

Я не спорю, а пытаюсь развеять заблуждение :)

Естественный кандидат на роль primary key в таблице пользователей — это уникальный идентификатор пользователя в системе (логин, мыло, ФИО, табельный номер, ИНН и т. п.), чаще всего текстовый, но с текстовым идентификатором работать неудобно и дорого (прежде всего в СУБД) и вводят суррогатный числовой в виде какого-нибудь id INTEGER AUTO_INCREMENT, который хоть и избыточен для бизнес-целей системы (то есть в бизнес-правилах он вообще не упоминается), но обеспечивает большее удобство и эффективность. Но он не является идентификатором пользователя в системе и, тем более, нельзя называть его получение результатом аутентификации. То, что его удалось получить максимум может служить признаком успешной аутентификации, т. к. он может быть получен только в результате успешной аутентификации. Она может быть не выделена явно в приложении, как, например при выполнении запроса SELECT id FROM users WHERE login='$login' AND password='$password', но её результатом является не id, а то что вообще нашлась запись где login='$login' AND password='$password'.
Пытаетесь развеять? А не много ли вы на себя берете, возможно, это вы заблуждаетесь?

Такое чувство, что вы прочитали пару лет назад статью про излишество автоинкрементных полей везде, где нужно, и где нельзя, и теперь применяете противоположный подход — избавляетесь от них и там, где они нужны, и там, где они не нужны.

Кстати, манера расстановки болдов еще раз подтверждает мое подозрение насчет наркомании.
Возможно и заблуждаюсь, но на ошибки вы мне не указываете.

Я от них отнюдь не избавляюсь (почти, только там где действительно не нужны, например в таблицах связи many-many), я просто сознаю для чего я их ввожу. И просто различаю понятия ключ (суррогатный) в БД и идентификатор пользователя в системе. И процессы аутентификации и получения этого ключа.

Что, болды это новый способ диагностики наркоманов? :)
А вот эти две фразы, отстоящие друг от друга всего на несколько слов, просто восхищают:
«нельзя называть его получение результатом аутентификации»
«он может быть получен только в результате успешной аутентификации»

Как люди, у которых ТАКИЕ пробелы в логике, могут быть программистами, я не понимаю. Впрочем, такие обычно становятся PM'ами, томно уверяя всех, что программировать им «надоело уже».
С логикой как раз всё нормально, сначала аутентифицируемся, а потом, если результат положительный (успешный), то получаем значение ключа для уже аутентифицированного пользователя.
Расскажите, пожалуйста, максимально подробно, как вы аутентифицируетесь, а как получаете значение ключа, а то у меня тут подозрения, что два этих процесса похожи как две капли воды, за исключением упоминания колонки user_id в списке колонок SELECT'a.
Не очень понял, как это связано с местом хранения сессии. Речь о производительности?

Может новое значение будет вписываться в момент обращения к записи.
homm спросил о том, как ему указать php, где лежит сессия, чтобы он в эту сессию смог положить текущий прогресс загрузки
В таком случае, я думаю, что это происходит автоматически. Было бы странно, если бы для этого пришло писать отдельные инструкции. Теряется весь смысл.
Круто. А в следующей версии языка разработчики сделают, чтобы приложение создавалось автоматически, а то я заколебался уже писать :)
Данная возможность уже запатентована компаний Adobe для Photoshop. Называется «Сделать п*****о»
Эм, в каком смысле «автоматически»? Откуда пхп узнает о том, куда подключаться и с какими логином-паролем?

Я всё таки подозреваю, что предполагается, что работать оно будет только с дефолтным хандлером
Мы говорим об автоматической записи размера залитой части файла после его отправки на сервер в сессию с определенным именем для данного файла? Если да, то запись будет происходит автоматически, если указана соответствующая настройка в php.ini или еще где.
Да, и она автоматически будет писаться в дефолтный хандлер, суть в файлы. А у человека — база, и он хотел бы писать туда (как и всё остальное у него) :-)
Добавляй «например», а то josser счас опять докопается :)
Чо сразу «докопается»?
Вы что не верите, что я действительно хотел знать для чего может захотеться хранить сессии в базе?
Если мы прикручивали базу данных для сессии через session_set_save_handler, то интерфейс доступа к сессиям не изменится. Так что PHP будет писать в базу, потому что PHP на том уровне не положено знать, где лежат сессии физически.

Если вы реализовали Свои Собственные Сессии, то PHP будет писать в файлы.
>> Если мы прикручивали базу данных для сессии через session_set_save_handler, то интерфейс доступа к сессиям не изменится
Кто и в какой момент будет запускать session_set_save_handler(), для инициализации калбэков?
html:


somescript.php:
session_set_save_handler();

if (is_uploaded_file… ()) // собсно сам аплоад.
Вот жеж,
вопщем там код формы с action=«somescript.php»
ПХП обрабатывает загрузку файла ПЕРЕД передачей управления в ваш код
Тогда я допускаю что это поведение было изменено в 5.4
А я не допускаю, потому что не было :-)
Т.е. нужно будет переписывать кучу кода, который не расчитан на то, что во время исполнения файлы еще не докачаны.
Не понял, покажите пример когда в коде уже известно о том что файл загружен но сам файл еще загружается.
В том то и дело, что такого не бывает, это вы придумали в своём коде
Я ничо не придумывал, это homm говорит что этот код надо переписывать.
Придумывали

>> Тогда я допускаю что это поведение было изменено в 5.4

Если это поведение было изменено, тогда весь код придётся переписать
Твое предположение было опровергнуто в моем самом первом комментарии:
> Upload делается перед запуском скрипта,
> поэтому поставить свои обработчики сессии
> в скрипте, который принимает закачку, нельзя.
Но кто же будет читать.

Твой наезд про гранение сессии в базе вообще не по адресу.

Теперь ты просишь привести пример кода, который был бы, если бы твое предположение о изменении поведения php было верным. Я вообще-то сказал что оно неверное, какой код я могу привести?

В общем что не комментарий, то бред какой-то. Завязывайте.
Я прошу привести пример кода который станет некорректно работать в случае если мое предположение верно.
<?php

copy($_FILES['file']['tmp_name'], '/path/to/file');


Вот конкретно этот код будет работать неправильно
$img = imagecreatefrompng($_FILES['image']['tmp_name']);
Про хранение сессий в базе, я второй раз напишу, никакой это не наезд. Где вы там увидели наезд?
Я ПРОСТО спросил. Мне очень интересен юс-кейс.
Пофилософствую на эту тему.
В самом первом вашем камменте речь шла о memcached. Что такое memcached? Система кэширования данных. Для чего служит кэш? Для ускорения доступа к используемым данным.

Какая есть брешь? Кэш не гарантирует сохранности данных, т.е. в любой момент при падении сервера или memcached'а все данные теряются.

С БД этого не произойдет, конечно, если тип таблицы не memory.

Такой ответ сойдет?
Клиент начинает загрузку файла во фрейм. Загрузка файла идет некоторое время. Мы хотим отрисовать прогресс-бар. Дергаем другой процесс PHP (но с теми же cookies) — получаем объем загруженной части файла.

То, что PHP не отдает нам массив $_FILES, ничего не меняет, потому что все, что нам нужно — узнавать раз в секунду загруженную часть.
И это никак не отвечает на вопрос о том, как пхп узнает данные о не-дефолтном хандлере для сессий

Я представляю как реализовывают прогресс-бар для закачки, потому и повторяю (а вы уходите от темы), что пхп (почти наверняка) будет писать в дефолтный хандлер, суть файлы
Я уже ставлю 5.4 в виртуалке, щас посмотрим как оно там. :)
Скорее всего, ответ: никак не будет вызван не-дефолтный хендлер.

Но проще всего проверить, PHP 5.4 уже в достаточно стабильной стадии RC5.
Очевидно, что никак :-)

Так что те, кто хранят сессии во всяких редисах теперь будут озабочены ещё и проблемой очистки старых сессий (совершенно верно, на продакшне никто не пользуется стандартным GC ведь)
Не понятно почему не пользуются.
Я вижу что в случае переопределения хендлера я также должен написать функцию delete для сессии.
Я подозреваю что GC использует ее для удаления сессий, не?
Эх…

Не пользуются потому, что GC непрогнозируемо замедляет выполнение скрипта. Потому и создаются задачи в кроне, которые подчищают старые файлы в директории
Мне-то она чем поможет? Я знаю об этой директиве.

И продолжаю утверждать, что в базе вы сессию хранить не сможете. На эту тему вы что-то добавите?
Нет, добавить нечего. Разве что соглашусь с утверждениями выше о том, что хранить сессии в базе — странно.
Данная информация не особенно полезна для запроса, непосредственно закачивающего файл, однако, в течение данной загрузки приложение может посылать POST-запросы на отдельную страницу (например, с помощью XHR) для проверки статуса.

Опции session.upload_progress.freq и session.upload_progress.min_freq контролируют частоту обновления информации о прогрессе загрузки. При разумных значениях этих двух настроек, накладные расходы данной функции практически неощутимы.
> в течение данной загрузки приложение может посылать POST-запросы
> на отдельную страницу (например, с помощью XHR) для проверки статуса.
Ну вот эта отдельная страница откуда-то берет информацию о процессе загрузки. Берет она её из сессии. В сессии эта информация как-то оказывается. Вопрос: как?
Для memcache так:
session.save_handler = memcache
session.save_path = "tcp://127.0.0.1:11211"

Для мускула не нашёл…
Хотя вариант с
session_save_handler(...);
session_start();

в скрипте-обработчике аякс запросов о статусе вполне может работать. Надо проверять или код php читать, пишет он прогресс файлов прямо в files сессию, или держит где-то внутри, пока сессия нужная не стартанет, а при старте туда добавляет.
Если он «внутри держит», т.е. напрямую из ОП в сессию внедряет, то зачем нужны настройки session.upload_progress.freq и session.upload_progress.min_freq? Просто всегда можно выдавать самые актуальные данные.
Чтобы не внедряться в процесс загрузки? Он периодически куда-то (разделяемая память, временный файл) пишет, а процесс индикатора считывает. По-моему, это проще, чем организовывать полноценное межпроцессное взаимодействие.
>> или держит где-то внутри, пока сессия нужная не стартанет, а при старте туда добавляет.
Тогда у прогресса будет только 2 состояния: 0% и 100%
Почему? При загрузке процесс управляющий загрузкой куда-то в память периодически пишет 0%, 1%, 2%… Когда сессия стартует, то она смотрит нет ли в памяти для неё этих процентов и читает их, если есть.
Тогда нужно в дополнение к работе с сессиями в этот алгоритм добавить какую-то разделяемую память.

Если бы она (разделяемая память) была — тогда сессии были бы совсем не нужны. Скрипты могли точно так же вычитывать прогресс оттуда же, без всяких прокладок в виде сессии.
Тем не менее это пока самый правдоподобный вариант.
Временные файлы на диске? Рядышком с закачиваемыми, а то и прямо в них.

А сессия нужна чтобы отделить файлы закачиваемые мною от файлов закачиваемых вами. Это, я думал, очевидно.
Если вы предлагаете данные временно хранить в разделяемой памяти — значит у вас достаточно информации, чтобы определить, где там чьи цифры лежат. Как следствие — прокладка в виде сессий для меня видится бессмысленной в этой схеме.

М?
> достаточно информации, чтобы определить, где там чьи цифры лежат
И эта информация — кука с идентификатором сессии, верно? (других идентификаторов клиента в спецификации HTTP не предусмотрено) Поэтому вполне логично, что и сама информация будет кластся именно в сессию. Тем более что в скрипте можно получать сессии для разных идентификаторов, если эти идентификаторы знать.
Нет. Для меня — нелогично.

Если данные временно кладутся в шаред мемори, то зачем их опять же временно потом перекладывать в сессию? Пусть скрипт сразу из памяти и читает. Зачем 2 временных хранилища?!
Мне-то кажется (и как я понял VolCh того же мнения), что данные и так читаются из shared memory, а в реальное хранилище сессий не попадают. Просто данные эти привязываются по тому же идентификатору сессии, подмешиваются в глобальный массив $_SESSION при вызове session_start().
Хм, хорошая версия, да, пардон за спор выше, если это так — то тогда всё ок.

Но я всё равно не верю :-)
Скрипт может прочитать нужные данные, только передав функции ид сессии. Получить он его может стандартно только стартанув сессию. При старте сессии он где-то внутри пхп и так передает ид сессии в session_start. то есть получим
session_start();
$pgress = get_uploading_progress(session_id());
И так в каждом скрипте, показывающем проценты. А механизм get_uploading_progress во многом аналогичен session_start(). Зачем плодить сущности?
«Примесь всегда имеет доступ к классу, к которому она подключена, через конструкцию parent.»

Читал, что traits работают по принципу copy-paste, т.е. их использование эквивалентно копированию кода trait внутрь класса, который его использует (use). Если это так, то parent совсем не нужен. В вашем примере должен и такой код заработать:

trait B {
public function bar() {
return $this->foo() . ' bar';
}
}
Наверное в данном случае вы правы. Parent более актуален, если в trait мы перезаписываем один из методов класса.
1. Как согласуются
>Parent более актуален, если в trait мы перезаписываем один из методов класса.
и
>Если имена методов класса и примесей совпадают, то приоритетным методом станет метод класса.
?

2. Что будет, если у примесей будут совпадать имена методов? Как-то можно обратиться к методу конкретного трэйта? А свойства в примесях есть, или придётся эмулировать их методами?

3. Unicode — это неожиданно. Думал, сделают только в PHP 6.
А как представлены строки в памяти? UTF-8?
А как обращаться к строкам по индексу? Не будет ли тормозов на длинных строках (например, при обработке файлов)? Ведь при обращении к $str[$i] не получится просто взять адрес $str и смещение $i — символы будут разной длины, придётся каждый раз отсчитывать с начала строки. Или символы в строке теперь индексируются дополнительно? :)
А что делать, если нужно считать из файла или db именно последовательность байтов, а не юникодную строку? Ну считать-то получится, но всякие str_replace и substr будут ожидать юникода?
1. Вы можете обратиться к методу, который переопределили через parent (как в обычном наследовании). Но если дергать метод без parent, то выполнится метод класса, а не примеси.
Порадовало название: примеси

код почти чистый, но с примесями :)
Осталось только устроить двойную перегонку и настоять :)
Traits позволят слабеньким программистам (см. индусам) такие вещи адовые писать, что и с тройной перегонкой не разберётесь :-)
Зато позволяют сильненьким программистам вообще почти ничего не писать.
по сути трейты штука относительно бесполезная.
DRY в некоторых случаях позволяет применять, когда раньше было нельзя или смысла не имело наследование вводить. Вообще собирались сделать, чтобы имели опциональное ограничение на имплементацию интерфейса классом, но не сделали. Теперь можем trait, вызывающий методы «потомка», применить к классу где этих методов и нет, а так могли бы применять какой-то фасад над интерфейсом только там, где интерфейс реализован.
Трейты могут быть очень удобны в MVC фреймворках, когда трейты выступают в роли хелперов и подключаются к контроллерам и моделям.

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

Хотя, вопрос спорный :)
для моделей есть бихейверы, которые как раз и делают то, что имитируют работу примесей. А трейты… подходят там где надо в классах писатьодно и тоже, например статический метод model у моделей Yii.
Имитация примесей через проксирование методов (если я вас правильно понял) жутко тормозит. Трейты будут нативны и, конечно, более производительны. Но нового они ничего не приносят, просто позволяют провести оптимизацию как производительности, так и чистоты кода.
С помощью трейтов брэзенхеймовская отрисовка линии на канвасе превращается в коллижн детекшн на гриде в три строки, например, и без всяких оверхедов. Я когда это сделал — просто таки офигел от красоты решения.
Вызов метода или свойства класса выражением уже давно было.

PHP 5.2.7
$ php -r 'class A{static public $foo_bar = "ok";} $foo = "foo"; $bar = "bar"; echo A::${$foo . "_" . $bar};'
ok

а, ну разве что вызова метода не было ($foo . '_' . $bar).
И то, только для статики:
class A
{
    public static function foo_bar()
    {
        return '123';
    }
}

$foo = 'foo';
$bar = 'bar';

$a = new A;

echo $a->{$foo . '_' . $bar}(); // 123
Вроде классический перевод для «traits» это «типажи», а «примесь» это «mixin».

Очень удивила новость про Unicode. Думал раньше 6.0 мы её не увидим, если вообще увидим. Type hints тоже порадовал, жаль, что не для всех скалярных типов. Тоже думал, что в 5.4 не будет, почитав бурную полемику по этому поводу.
Тоже удивлен, что появилась наконец-таки поддержка Unicode.
А на выход PHP 6.0 я уже давно вообще и не надеюсь.
Очень рекомендую к ознакомлению статью «Как умер PHP6». Там в частности расскзаывается, как пытались прикрутить юникод к PHP.
По-моему, просто неверно понятый ченжлог. Или очень старая информация. Как не рыл php.net вчера и сегодня, максимум, что нашёл это, что парсер корректно обрабатывать должен исходники с мультибайтовыми кодировками (вроде были проблемы с азиатскими) и BOM в начале utf файла (частая ошибка для тех, кто пишет сайты в Блокноте :) ). Про переписывание всех строчных функций речи нет, а mb_string_overloading 100 лет в обед.

Когда-нибудь да выйдет. Не будет же PHP5.24 :) Другое дело, что там в фичах будет, Unicode похоже не дождёмся :( А так больше всего жду, когда же наконец объявят зоопарк функций depricated и сделают их «алиасами» к стандартизированным функциям/объектам с единой системой именования и парметрами. Ну и scalar type hints хочется.
А я работаю с бинарными данными, я не могу вот так вот перегрузить функции.
«mixin» и «примесь» — одно и то же, трейт и миксин — несколько разные вещи.
То есть месяца через 3-4 хостеры обновят свой php и забываем об функциях mbstring?
Hell Yeah!)))
Сомневаюсь, что 3-4 месяца. В Debian, например, сейчас только 5.3.3 (19 месяцев), в Ubuntu 5.3.6 (10 месяцев) при текущей 5.3.9 (полмесяца).

Плюс не очень понятно что с обратной совместимостью. Вряд ли хостеры рискнут сразу так менять, чтоб клиенты вайн начали.
В смысле через года 3-4?5.3 вышел в 2009-м, до сих пор на шаредах его не видно особо :(
И шаблонные решения типа cms/framework начнут глючить местами и прочие скрипты… У нас вот и до 5.3 проблематично обновиться, т. к. drupal 5 официально не поддерживает 5.3 (некоторые модули начинают косячить).
UFO just landed and posted this here
А можно будет указать тип возвращаемого значения, а не только аргументов? Вот это было вы действительно круто
Давно уже можно, но там преобразование типов происходит.
В смысле давно? С какой версии это уже давно можно указать тип возвращаемого значения ф-ции или метода
Вы имеете в виду

function foo() {
  $a = 1;
  return (string) $a;
}
Сможете такой же финт повторить с классом?
И то и то — это преобразования типов, а те type hinting.
Значит я не прав. Извините, что ввел в забуждение.
Ну да. Собственно без указания типа самой переменной тип возвращаемого значения смысла не имеет практически. Согласен
Чтобы писать
int function foo() {}
вместо
/**
@return int
**/
function foo() {}
/* это может понадобится только для того, чтобы IDE intellisence правильно подставляла, ну так это же делается
@return MyClass
*/
Примеси — это чертовски интересно, надо покопать глубже. А новость о типизации — это хорошо, может таки к шестой версии будет реализовано для всех типов
вот и моя логика забуксовала на текущей дате :) сразу вспомнил бородатый анекдот про логику программиста:

Жена посылает программиста в магазин:
— Дорогой, купи, пожалуйста, палку колбасы, и если будут яйца, то купи десяток.
Через полчаса программист возвращается с десятью палками колбасы.
Жена:
— Что это?! Зачем ты купил столько колбасы?
Программист:
— Ну так яйца-то были…
11 палок. Первое выражение выполняется независимо от второго, возвращает истину и затем выполняется второе выражение с условием.
Нет там scalar type hints. Тут всё пересмотрел — нет там такого.

Оттуда же:
«Added zend.multibyte directive as a replacement of PHP compile time configuration option --enable-zend-multibyte. Now ZE always contains code for multibyte support, but may enable or disable it by zend.multibyte. It doesn't make a lot of sense to enable this option without ext/mbstring, because the most functionality is implemented by mbstrings callbacks.»

Насколько я понял расширение ext/mbstring всё равно нужно.
Расширение остается, но, насколько я понял, явных вызовов mb_* не будет.
Вы правы, скалярный typehinting убрали уже давно из ветки 5.4. Автор статьи явно использовал устаревшую информацию.
Больше всего жду встроенный веб-сервер. Даже index.php уже готовлю для него
Тоже заинтересовало. Не попробовать в боевых условиях или еще где-то — просто грешно.
В боевых вроде как не советует, это же мини сервер все таки. При больших нагрузках неизвестно что с ним будет.
Поддержка Юникода — это здорово! Но сразу вопрос: как поведут себя разные там strlen()? Будут ли они возвращать длину строки в байтах или в символах?
А это в свою очередь означает, много проблем, когда разработчик работал с двоичными данными. Например fwrite. Кстати а обращение к элементу строки по индексу $str[$i] будет символ возвращать или как и раньше 1 байт?

Соответсвенно вопрос — как получать strlen в байтах?
Да, я уже сейчас понимаю, где и что придётся переписывать — и это оптимизма не добавляет, несмотря на то, что новость скорее положительная.

Лучше оставили бы поведение прежним, но добавили дополнительный параметр, который переключал бы strlen в режим работы с Юникодом.
Ну, а как сейчас получают длину в байтах, если включен оверлоадинг и внутренняя кодировка UTF. Правильно, с помощью функции mb_strlen :-)
У нас для этого специальная функция есть…
Она builtin. Какя понимаю просто пропатчили модуль для этого
Хорошие новости. Ибо примеси в Ruby очень гармоничны с модулями и нэймспэйсом, как с этим будет в PHP?

Больше порадовало, что будет изменена работа с массивами, еще со времён работы с Perl всё удивлялся почему нельзя сразу получить и работать с массивом который выглядит очевидно.

PHP радует последние 2 года, растёт и усложняется, что позволит и повышать зарплаты на разработчиков тоже :)
Про юникод, на самом деле, очень грустно, потому что сломается очень большое количество кода. Если раньше можно было работать с байтами (если пишешь данные куда-то в сеть, в базу или ещё куда), а можно — с символами, то теперь strlen() неожиданно начнёт отдавать символьную длину. Хотя в доках пока изменений нет, и есть надежда, что режим unicode будет включаться параметром.
Как часто нам нужно дернуть нулевой индекс у метода, который возвращает массив?

С *нулевым* можно reset(foo());
Более того — если метод возвращает данных больше, чем нужно — тогда этот метод в первых рядах на переписывание.
Нельзя, если вы хотите писать код в соответствии со strict-стандартом:
function test()
{
    return array('first', 'second');
}

print "\n";
print_r(reset(test()));
print "\n";


imenem@localhost:~
$ test

PHP Strict standards:  Only variables should be passed by reference in /var/www/bank-soft.local/www/test.php on line 21
PHP Stack trace:
PHP   1. {main}() /var/www/bank-soft.local/www/test.php:0

Strict standards: Only variables should be passed by reference in /var/www/bank-soft.local/www/test.php on line 21

Call Stack:
    0.0001     634352   1. {main}() /var/www/bank-soft.local/www/test.php:0

first


Но вы можете получить первый элемент массива так:
function test()
{
    return array('first', 'second');
}

list($first) = test();

print "\n";
print_r($first);
print "\n";
Таки да, почему-то не обращал внимания, спасибо.
Ну можно же построить эту связку самому используя try-catch. И идеалогически это более правильно.
А как это сделать на try-catch? Foreach по пустому массиву не кидает ексепшн, ведь.
Пробовал применять в языках где она есть — не понравилось, задачу получения семантического html не решает, по-моему. Максимум что можно получить без костылей это
<ul>
  <div>There are no items</div>
</ul>

вместо желаемого
<div>There are no items</div>

Или я семантику <ul> не понимаю?
Может я не туда смотрю, но тут svn.php.net/viewvc/php/php-src/tags/php_5_4_0RC6/UPGRADING?view=markup ничего не сказано про нативную поддержку юникода, только о том что в php.ini по умолчанию теперь default_charset будет utf-8. Из-за неудачи с юникодом как раз и была выпилена 6-ая ветка.
Именно так. Автор вообще много напутал в статье в спешке.
Вы смотрите тэг RC 5.6. Т.е в нем изменения, присущие исключительно шестому релиз-кандидату. Некоторые вещи были реализованы раньше, некоторые могут попасть в стабильный релиз. К тому же для создания этой статьи я мало использовал официальные источники. В основном в статье перечислены вещи, которые появятся или могли появится, из-за того, что в свое время кто-то из разработчиков «слил» информацию.
Вообще говоря я пробегал глазами ченжлоги начиная от первой альфы, да и ещё почитывал разные источники и очень удивлен увидев поддержку юникод и тайп-хинтинг для скаляров. Дефолтный чарсет utf-8 и включенная по умолчанию поддержка multibyte — вроде всё, что unicode касается. А ченжлог по ссылке, по-моему, куммулятивный. В RC по идее только баги правят, новые фичи не вводят.
РНР окончательно пошел по пути «в каждый минорный релиз будем впихивать столько изменений, что другим языкам хватает на смену мажорной версии» :)
А разьве в PHP было множественное наследование?
Нет. Есть множественная имплементация интерфейсов.
Нет. Просто не все могут быть в курсе, что такое примеси. О том, что такое множественное наследование — известно большему числу людей.
А, ясно, а то я удивился, погуглил и ничего не нашёл.
foo()[0]; — вот это круто,
еще жду foo()(0); — это если функция возвращается
- Class member access on instantiation:
(new foo)->method()
(new foo)->property
(new foo)[0]

Ещё из приятного
Array dereferencing support, Short syntax for arrays и что-то еще делают php похожим на js. Сколько раз после написания яваскриптов возвращался на сервер и спотыкался. Вообще, весь список изменений выглядит очень вкусно для разработчика.
Но как-то мелко что ли? 5.3 поглобальнее был.)))
Это в очередной раз показывает, что нет единой системы выражений, что выражения имеющий вроде бы одинаковый тип ведут себя по разному в зависимости от того откуда этот тип появился.

Может быть вы удивитесь, но Array dereferencing support и т. п. в JS появились из C (а там, вроде, из B), причём специально их никто не вводил, просто [] не зависит от способа вычисления expr и index, достаточно чтобы они были нужного типа или приводились к нему автоматически.
Scalar type hints, Array dereferencing support я ждал это, я ждал этого всю жизнь =)
Вызов метода или свойства класса выражением выглядит уже страшно
А, забыли ж одно из главных: теперь Closure понимает $this
Это мелочи, а вот теперь можно будет не писать E_ALL | E_STRICT, а просто E_ALL :)
Как сказать, мне этого таки нехватало.
Смайлик должен был сказать, что серьезно относиться не стоило.
Чёрт, я подумал, что у вас выражение в скобках. гг
А можно было всегда писать error_reporting(-1); что эквивалентно, и короче :)
Магическое число?
php > printf("%u", -1);
18446744073709551615
Ну давайте по длинному пути.

Функция error_reporting принимает в качестве аргумента битовую маску, которую можно составить из предопределенных флагов. Число -1 же в битовом представлении представляется 64-я единицами (для 64-х битных чисел). Поэтому числу -1 соответствует максимально полная битовая маска. Правильную ссылку нужно было давать на часть статьи «Числа, которые не являются магическими». Так-то.
Это лишь привычное вам битовое представление (так называемый дополнительный код). Вроде в PHP оно не декларировано и может меняться в зависимости от платформы.
Нет, полная битовая маска :)
Очень здорово. Особенно синтаксический сахар, Unicode, встроенный девелоперский сервак и выпиленные deprecated.
Да не будет нормальной поддержки Юникода. Utf-8 по умолчанию (вместо iso-8чего-то там) и zend.multibyte boolean
Разрешает парсинг исходных файлов в многобайтных кодировках.

detect_unicode boolean
Определяет, нужно ли проверять BOM (Byte Order Mark, метка порядка байт) и корректность многобайтных символов в файле. Эта проверка производится до вызова __halt_compiler(). Доступна только в режиме Zend Multibyte.

Всё.
> Встроенный веб-сервер

Нахернадо.

> Улучшена производительность @

Нахернадо. Ну как бы нелишне, но теперь криворукие кодеры будут вставлять её везде и всюду наивно думаю что мол теперь так делать «можно».

А вот всё остальное — очень даже надо, круто!
Подскажите кто-то, я понимаю что @ зло и в большинстве случаев не использую, но вместо такой строки:
logSomething($_SERVER["HTTP_REFERER"], ..., ...);

мозг упорно не хочет писать
logSomething(isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "", ..., ...);

вот именно в данном случае, не проще ли так?
logSomething(@$_SERVER["HTTP_REFERER"], ..., ...);

Имхо, @ следует применять только если тут же организовывать разбор c помощью error_get_last()

А по вашему примеру сходу и не врубиться, что именно вы хотите подавить.
Ну кстати для тернарного оператора есть более удобная форма записи, которая введена в ПХП 5.3. А злостная сущность собаки заключается в том, что она усложняет дебаг. Но уже это есть вполне даже веская причина отказа от её использования.
Хм… да, новый тернарный выглядит намного лучше, сэнкс.
logSomething($_SERVER["HTTP_REFERER"] ?: "", ..., ...);
Не совсем эквивалентно вашему первому коду: PHP Notice: Undefined index: HTTP_REFERER in - on line 2
$_SERVER["HTTP_REFERER"] ?: "" эквивалент $_SERVER["HTTP_REFERER"] ? $_SERVER["HTTP_REFERER"] : "", но не isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "" Интересно появится ли когда-нибудь.
Блин, точно. Выходит всё равно пока красивее собаки не выходит. Да и недостатков вроде нет.
Главный недостаток, что если ошиблись в написании HTTP_REFERER или _SERVER, то никогда ошибки не заметите понимание почему все пользуются анонимайзерами или «умными файерволами» может быть затруднено. Анализ и логирование error_get_last() облегчит задачу и позволит, например, вычислить тупых ботов. Поэтому я если и ввожу @, то сразу после него идёт вызов error_get_last().
Удобно для тестирования, не заморачиваясь с локальной установкой сервера и его настройкой на каталог проекта. Оценивал по другим ЯП. Действительно удобно.
Встроенный веб сервер: php -S localhost:8000
Теперь кодить php на андроиде станет проще. Т.к. не нужно держать дополнительный веб-сервер.
Блин, а я-то думаю, чего в ченжлогах не хватает… Печаль :(
А я будучи админом именно этого ждал…

Articles