программирование

PHP, UTF-8: восьмой этап, заключительный

Прошло уже немало времени, с тех пор как я описал предыдущий этап перевода на UTF-8 нашей внутренней Вики. Этот этап заключительный, после него пришлось поправить несколько шероховатостей и сегодня с него, так сказать, сняли строительные леса.

Что же дальше?
Последний этап — много ручной мороки, всякие мелочи и прочие вещи подобного уровня.

Для начала надо понять что же делать с чтением и записью файлов. Нет никакого автоматического способа решить что делать с этими операциями в вашем проекте, хорошие новости заключаются в том, что, скорее всего, ничего делать не придётся.

Мне не пришлось, хотя, чтобы это понять, нужно было исследовать исходники. Побайтовое чтение файлов — редкая операция в мире веб-приложений, гораздо более частая — чтение в буфер или по переводам строк. В обоих случаях (а чтение по переводам строк работает и с UTF-8 без изменений) нужно следить, чтобы буфер не кончился на середине символа, если, конечно, вы производите с содержимым какие-то манипуляции, а не просто копируете его куда-то дальше.

Даже в том случае, если вы производите с файлом какие-то операции, не всегда может понадобиться что-то изменить в коде, чтобы он работал с UTF-8. Например, если в файле заменяются однобайтовые символы (все символы с кодом меньше, чем 128), то проблем не будет.

Для другой операции, нам понадобится четыре метода в классе работы с UTF (напоминаю, что константа ON этого класса определяет включена ли поддержка UTF): метод charset возвращает «windows-1251» или «UTF-8» в зависимости от флага ON, метод charsetCP возвращает «CP1251» или «UTF8», метод from1251 перекодирует из cp1251 в UTF-8, если ON установлен в false, иначе возвращает строку как есть, метод to1251 перекодирует обратно, если ON установлен в false, иначе возвращает строку как есть.

Замены очевидны: везде, где в коде встречается «windows-1251» я поставил вызов метода charset, там где cp1251 — charsetCP, там где используется перекодирование (функции iconv, mb_convert_encoding, recode, recode_string) вызываем соответственно from1251 или to1251.

Потом нужно проверить все места, где встречаются вызовы chr и ord («egrep ’\\b(ord|chr)’ -R .») и проверить не нужно ли переписать какие-то места (я не помню писал ли я об этом уже).

После этого осталось только перекодировать исходный код:

# вот эти файлы перекодировать не надо, они у меня уже в UTF-8
SKIPIT='./php/Utf.php|./php/UtfReverseString.php|./php/UtfString.php'
tmp=`tempfile`

for line in $(find -name '*.php' -or -name '*.tpl' -or -name '*.inc' | egrep -v "$SKIPIT"); do
    iconv -fcp1251 -tutf8 "$line" -o "$tmp"
    [ -e "$tmp" ] && mv -f "$tmp" "$line"
done

И базу:

mysqldump -pпароль -uпользователь --add-drop-table --create-options --default-character-set=utf8 --order-by-primary -q база |
sed -e 's/cp1251;$/utf8;/mg' |
mysql -pпароль -uпользователь база

В процессе пуска проекта выяснилась ещё одна немаловажная подробность (спасибо Саше Покатилову): оказывается, несмотря на то, что установки локали (setlocale) никак не влияет на функции сортировки в PHP, она влияет на некоторые функции работы с файлами (dirname, basename и некоторые другие), вот цитата из описания функции dirname:

dirname() is locale aware, so for it to see the correct directory name with multibyte character paths, the matching locale must be set using the setlocale() function.

Поэтому не забывайте выставлять локаль, если пользуетесь этими функциями.

В общем-то, это всё, после выполнения всех описанных мною операций, проект заработал.

Дополнено: внезапно нашлись неприятные грабли, будьте осторожны: функция preg_match_all (и preg_match) с ключём PREG_OFFSET_CAPTURE возвращает бинарное смещение в строке (т. е. указывающее не на байт, а на символ), даже в UTF-режиме со включенным «глаголом» UCP.

Я поступил просто — написал простую функцию, которая корректирует выходные значения. Идея простая: отрезаем при помощи substr строку до смещения, потом измеряем её UTF-8-длину. Тут важно не забыть, что preg_match может вернуть смещение -1, если совпадение было пустым.

Еще позднее: оказывается и параметр offset (последний параметр в preg_match и preg_match_all) работает с бинарным смещением, а не с UTF-8.

И ещё позже: а вот вам ещё сюрприз: модуль Multibyte String считает, что кодировка UTF-16 это UCS-2BE, тогда как iconv кодирует правильно.

И ещё сильно позже: strftime тоже использует локаль.

6 комментариев

Даже создатели Dojo не читают документацию

Почему-то всегда хочется думать, что создатели больших фреймворков уж точно детально изучили вопрос. Между тем, они обычные люди. Как известно, в реализации JavaScript в IE нет сеттеров и геттеров. Зато они есть в VBScript (который кажется куда более проработанным языком в IE):

Class Sample
  Public Property Let someprop(val)
    …
  End Property
  Public Property Set someprop(val)
    …
  End Property
  Public Property Get someprop
    …
  End Property
End Class

Два вида сеттеров связаны с тем, что в VBScript довольно чётко различаются передача по ссылке и по значению (например, можно в параметрах функции указать «ByRef» или «ByVal»), кроме того, у сеттеров и геттеров есть ещё один параметр, благодаря чему можно перехватывать вызов методов и делать совсем уж странные, с точки зрения JavaScript, штуки.

Впрочем, к чёрту подробности.

Один из разработчиков JS-фреймворка Dojo реализовал в нём эмуляцию сеттеров и геттеров для IE, но в его примере есть некрасивая штука — глобальная функция dj_exec_vb_global, которая описана внутри тега SCRIPT с указанным языком VBScript и предназначена для вызова VBScript из JavaScript.

Но в IE уже есть специальный метод объекта window, который занимается тем же — execScript, вторым параметром надо задать «vbscript» и voilà!, мы вызываем VBScript из JavaScript.

Я этот метод когда-то использовал внутри JUnix (это был эмулятор CLI Linux на JavaScript).

6 комментариев

Как заменить одну строку на другую в файле (Linux)

Устал я от долгих споров, давайте что-то на техническую тему напишу. Тем более, что после двух писем с одним и тем же вопросом и одного поста внутри компании, оказалось, что такая простая вещь тянет на рецепт: как можно в bash заменить в файле одну подстроку на другую.

Вот несколько способов, которые я знаю.

Во-первых, в состав MySQL входит замечательная утилита replace, которая замечательна тем, что умеет производить замену прямо в файле:

replace 'hello' 'bye, bye!' -- myfile

Самое замечательное, что она умеет менять пары подстрок, что позволяет производить такие замены:

bolk-dev ~ $ echo ABBA | replace A B B A  --
BAAB

Второй способ — создать временный файл, заменить в нём символы или подстроки какой-нибудь утилитой (sed, tr), переместить временный файл на прежнее место (не забудьте, что sed работает с регулярными выражениями):

T=`/bin/tempfile`
sed 's/hello/bye, bye!/g' myfile > $T
mv $T myfile

Сразу в тот же файл записывать результат нельзя, операция „>“ сразу же откроет файл на запись и обнулит его. Поможет утилита sponge (входит в пакет moreutils):

sed 's/hello/bye, bye!/g' myfile | sponge myfile

Она запишет stdin в файл разом, после того как все данные будут получены.

Добавлено: Азат в комментариях подсказывает, что можно воспользоваться ключом «-i» у sed:

sed -i 's/hello/bye, bye!/g' myfile

19 комментариев

Кроссбраузерный data URI в CSS-файлах (подробно)

Кстати, всё забываю порекомендовать статью Banderlog’а, который написал её по мотивам моей статьи «Кроссбраузерный data URI в CSS-файлах», прекрасно разложив всё по полочкам и детально проработав тот же подход в форматах PNG и GIF.

Статья на Хабре называется «К вопросу о кроссбраузерных Data URI».

Оставить комментарий

Что за проект я перевожу на UTF: FAQ

Wiki на UTF-8 (55.74КиБ)

Из комментариев на одном из сайтов Димы видно, что люди делают какие-то совершенно дикие выводы относительно моей эпической борьбы с UTF-8 в PHP. Кстати, она окончена, остались мелочи, доделки и доводки. На скриншоте — уже бета.

Так что небольшое FAQ.

В: Долго ещё до конца сериала? О: Следующая часть будет последней.

B: Что за проект переводится на UTF-8? О: Это внутренняя Вики, основанная на ВаккоВики, дописанная за годы использования и интегрированная с остальными внутренними сервисами. Её нередко можно встретить на слайдах презентаций «Яндекса».

B: Зачем переводится? О: Все остальные внутренние сервисы «Яндекса» на UTF-8, что делает задачу интеграции Вики иногда чрезвычайно сложной, кроме того, есть большая потребность научить нашу Вики работать не только с русскими и английским, но и с другими языками.

B: Нельзя ли переписать это всё на другой язык, где нет проблем с UTF-8? О: Можно, но это человеко-годы, я справился намного быстрее.

В: Зачем нужно было всё автоматизировать? О: Во-первых, автоматизированно было далеко не всё, некоторые места я искал в автоматическом режиме, а изменения приходилось вносить руками, во-вторых, всего было сделано несколько тысяч замен, можно ли такое количество заменить вручную, да ещё и не ошибиться?

В: Почему бы нанять сотню студентов, за копейки, чтобы они сделали замены руками? О: За этими студентами нужно проверять работу, кто это будет делать? Я за собой вычитывал исходники, распечатывал листы diff’ов, уходил куда-нибудь в переговорку и работал с бумажками — выделял карандашом проблемные места, потом новая итерация. Со скриптом проще — в одинаковых ситуациях он споткнётся одинаково, сотня студентов споткнётся сотней разных способов.

21 комментарий

PHP, UTF-8: седьмой этап, давайте что-нибудь сделаем с регулярными выражениями

В прошлый раз я рассматривал, по сути, самый сложный этап — замену всех вхождений $var[$index] и им подобных на вызов моей функции. В процессе замены я несколько раз корректировал заметку и доводил некоторые вещи руками.

Что же дальше?
Осталось совсем немного, но я столкнулся с неприятной проблемой.

В самой первой части я рассказывал о том как можно решить проблему с UTF-8 в регулярных выражениях — нужно поставить «глагол» (в терминах PCRE) UCP и добавить модификатор «u». Тогда в PCRE начинают адекватно, по отношению к UTF-8, работать «\w», «\W», «\s», «\S» и т. п.

К сожалению, этот «глагол» появился только в PCRE 8.10, а в самом последнем PHP, на сегодняшний момент, содержится 8.02. Как я говорил ранее, новый PCRE можно вкомпилить в PHP при помощи специального ключа.

Внутренние сервисы, где я работаю, используют Debian-системы и Debian-пакеты, все наши проекты выкладываются через эти пакеты. Чтобы поставить нестандартный PHP+PCRE, нужно собрать три пакета (php-cgi, php-cli и модуль к Apache).

Поскольку мы сейчас переходим постепенно на новую версию Ubuntu (с Hardy Heron на Lucid Lynx), то часть машин у нас пока на Цапле, а часть — уже на Рыси. Это значит, что пакетов нужно будет собрать шесть.

Дело это непростое. Я решил попробовать «выдрать» из внутренностей PHP модуль PCRE, переименовать его функции и константы и поставить его как простой подключаемый модуль.

Мне удалось сделать, модуль «свежего PCRE» (можно скачать в разделе «Храню»). Модуль называется ygx, все функции начинаются с префикса «ygx_», константы — с «YGX_».

Что это за сокращение, не спрашивайте, когда я начинал работать, я это знал, а сейчас забыл.

Сложнее всего было корректно переименовать только те функции, типы, константы и так далее, которые видно в PHP, не задев всё то, что импортируется из внешней библиотеки PCRE.

Ставится модуль примерно следующим образом:

mkdir /tmp/pcre
cd !:1
wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.10.tar.bz2
tar xvfj pcre-8.10.tar.bz2
cd pcre-8.10
./configure --prefix=/usr/local/pcre-8.10 --enable-utf8 --enable-unicode-properties --disable-static
make && make install
cd -

wget /files/php_fresh_pcre.zip
unzip php_fresh_pcre.zip
phpize
./configure --with-ygx-regex=/usr/local/pcre-8.10
make && sudo make install
phpize --clean
cd ; rm -rf /tmp/pcre

потом нужно прописать в php.ini строку «extension=ygx.so», перезапустить на FastCGI-сервер или веб-сервер с модулем PHP (смотря чем вы пользуетесь) и, вуаля, у вас есть новые функции — ygx_relace, ygx_match и т. д.

Поскольку к этому моменту все вызовы функций PCRE у меня заменены на вызовы одноимённых методов статического класса UTF, то мне нужно поменять «preg_» на «ygx_» только в одном месте — внутри методов этого класса.

3 комментария

ICQ опять пытается стряхнуть альтернативные клиенты

На данный момент не подключаются QIP, Jimm и Miranda (возможно ещё какие-то клиенты), выдаётся сообщение «The server did not accept this client version». R&Q и Infium работают.

Добавлено позднее: удалось соединиться через Миранду 0.9.9b1, выключив «Secure connection (SSL)».

23 комментария

Flashblock в «Опере»

Оказывается, в «Опере» 10.50 и выше есть встроенный аналог плагина «Flashblock» для Firefox — опция «opera:config#UserPrefs|EnableOnDemandPlugin» (вставьте в адресную строку и нажмите Enter, увидите соответствующую настройку).

Опция включает функционал, который мне хотелось включить по-умолчанию с тех пор как я увидел Opera Turbo — в этом режиме Flash не загружается до тех пор, пока на него не кликнешь.

15 комментариев

IE9 и CSS3 2D Transforms

Появился Internet Explorer 9 PP6, из интересного — появилась поддержка 2D-трансформаций из CSS3 (свойства -ms-transform и -ms-transform-origin).

Кроме того, появилась поддержка семантических тегов HTML5 (section, nav, article и так далее). Раньше при разборе дерева элементы, содержащие эти теги наследовались от HTMLUnknownElement, теперь — от HTMLElement.

8 комментариев

Stoyan Stefanov

Стоян Стефанов (21.39КиБ)

Стоян Стефанов (архитектор YSlow, автор нескольких книг по JavaScript и ряда любопытных исследований) сейчас в «Яндексе» рассказывает лекцию. К сожалению, я пойти не смог, а жаль:

— Болк, а ты чего не на Стояне? Он тут тебя упомянул =)
— Э… как это?
— Он щас в Яндексе читает лекцию, ну и типа сказал вот крутой чувак (и твоего блога скриншот)

Hello, Stoyan! Sorry I could not attend your lecture.

4 комментария

PHP, UTF-8: шестой этап, она же «строки, часть II». Заменяем

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

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

Код я выкинул и начал писать заново, основываясь на токенах (лексемах), которое выдаёт встроенное в язык API токинайзера. По ходу процесса я часто уточнял случаи и производил тестирование. Получился довольно неряшливый парсер, к тому же с некоторыми багами, которые я счёл несущественными. Например, не обрабатывается ситуация isset($var, $var[$idx]).

В PHP isset (а так же empty и unset) — конструкции, а не функции и принимают на вход только переменные. У меня получение символа по индексу заменяется на Utf::get(…), а внутри строки на другую конструкцию — $_ENV[0x5f3759df]->get(…), так что если произойдёт замена внутри isset, будет синтаксическая ошибка.

Т. е. у меня в коде, внутри файла с классом Utf есть ещё и такая строка — «$_ENV[0x5f3759df] = new Utf();». $_ENV я выбрал за то, что это переменная (а переменную внутри строки проще заменять на другую переменную, пусть и с вызовом метода, PHP это позволяется) и это, в терминах PHP, «суперглобальный» массив, то есть он доступен отовсюду.

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

Первая операция, которую вам нужно сделать ещё до запуска парсера — это запустить следующий скрипт. У меня парсер работает с UTF-8, а исходники у меня пока ещё в CP1251. Так что парсер сначала перекодирует код в UTF-8, потом обратно в CP1251. Но я беспокоился — не испортит ли двойная перекодировка что-то в исходниках.

Так что я перекодировал код туда и обратно и сравнил что получилось:

for file in $(find -name '*.php' -or -name '*.inc' -or -name '*.tpl'); do
    sum_new=`iconv -fcp1251 -tutf8 "$file" | iconv -futf8 -tcp1251 | md5sum -b | cut -d' ' -f1`
    sum_orig=`md5sum -b "$file" | cut -d' ' -f1`

    if [ $sum_new != $sum_orig ]; then
        echo $sum_new $sum_orig $file
    fi
done

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

find -name '*.php' -or -name '*.inc' -or -name '*.tpl' | xargs php -l

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

Добавлено позднее: а вот как выглядит метод get в классе Utf:

static public function get($str, $index)
    {
        if (!is_scalar($str)) {
            return isset($str[$index]) ? $str[$index] : null;
        }

        return self::substr($str, $index, 1);
    }

Добавлено позже: нашёл ещё два бага: неверно отрабатываются «$prop[$idx]->value» и «$str[$idx] ==». Второе надо править в регулярном выражении. Я их править не буду, они запросто ищутся утилитой «grep» и правятся руками. Кроме того, не заменяются переменные в heredoc (мне это не нужно).

Конструкции heredoc я нашёл при помощи «grep -FR ’<<<’ *» и просмотрел их все, их было очень мало и ни одна из них не содержала переменных.

Добавлено ещё позже: опаснее оказалась ситуация, которую просто так можно и не заметить: замена вызова func($var[$index]) на func(Utf::get($var, $index), где прототип func описан как func(&$var). Синтаксис PHP вполне допускает такие ситуации, а на деле в массив могут не попасть изменения, которые должны были переданы быть по ссылке.

Способов исправить такую ситуацию два. Первый — логгировать все вызовы Utf::get, которые применяются к массивам и править их на получение переменной по индексу. Второй — найти и просмотреть все такие ситуации. Я выбрал второй способ:

find \( -name '*.php' -or -name '*.tpl' -or -name '*.inc' \) |
xargs egrep -oh 'ion[\t ]+\w+[\t ]*([^{]+' | awk -F'[( ]' '/&\$/{print tolower($2)}' |
sort -u | egrep -v '^preg_' | xargs -I{} egrep -iR  --exclude-dir=.svn {}'[\t ]*(.*?Utf::get' *

Этот скрипт (который очень долго работает) показывает все подозрительные строки (у меня их 7 оказалось), их надо просмотреть, выявить потенциально проблемные и поправить, если проблема действительно есть.

И ещё позже: так же есть набор встроенных функций, которые используют передачу массива по ссылке, я их нашёл вот таким способом:

(cat<<FUNCS
'\b(?:array_multisort|array_pop|array_push|\
array_replace_recursive|array_replace|\
array_shift|array_splice|\
array_unshift|array_walk_recursive|\
array_walk|arsort|asort|current|each|\
end|key|krsort|ksort|natcasesort|natsort|\
next|pos|prev|reset|rsort|shuffle|\
sort|uasort|uksort|usort)[ \t]*\([\t ]*[^$)]'
FUNCS
) | xargs -I[] find \( -name '*.tpl' -or -name '*.php' -or -name '*.inc' \) -exec \
egrep [] {} \; -print

4 комментария

Вышла альфа «Оперы» 11 с расширениями

Это очень хорошая новость — вышла 11-я «Опера» с поддержкой расширений. Например, уже появилось расширение «Opera to Phone», к которому я привык на «Хроме».

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

Из других хороших новостей — появилась поддержка WebSockets.

Добавлено: а ещё можно добавить сервисы «Яндекса» — пробки, погоду и отзывы о текущей странице.

7 комментариев

Карго-культ личности

Это настолько смешно (для тех, кто понимает), что хочется процитировать полностью. Но только избранное:

Также пока меня не было (последние 2 недели я особо не писал в блог) удалось слить движок Nudnik.ru.

Движок очень хороший. Не побоюсь этого слова Мастер Смирнов постарался на славу (демо естественно у него на его сайте). Но также очень много файлов которые вообще не нужны.

Также есть аспекты в php когда функцию можно обработать в одну строчку, а он зачем-то бабахает в 5-ть. В результате все это добро весит 25 мб. Но это добро не грузит хостинг — это радует. А также он требует PHP 5 версии, а значит Смирнов «ухаживает» за своим детищем.

А также товарищ Болк постарался с движком. И естественно «намудрил» с ним, где разберется только он сам.

Кстати, руку могу дать на отсечение, что движок Димы весит меньше сотни кг, написан без всякого форматирования и не использует буквально ничего, что появилось в PHP5.

Кстати, Дим, а кто этот Кирилл Котиков, какой-то твой фанат?

11 комментариев

404fest: было здорово!

Всё забываю написать, на «404» в Самаре было очень здорово. И уровень докладов, и развлекательная программа, и люди! Увидел старых друзей и знакомых — Илью Бирмана, Вадима Макеева, Сергея Чикуёнка, ребят из «knock knock» и многих других. Приобрёл новых знакомых и, как я надеюсь, друзей.

404fest (51.01КиБ)

Вообще, сейчас какое-то время будет редко получаться писать — сильно занят. На работе занимаюсь очень плотно этой проблемой перевода проекта на UTF-8, дома — сменой дизайна сайта.

Сайту скоро 10 лет, его посещают в день от 2 до 5 тысяч человек (в зависимости от дня недели), читают чуть меньше 90 тысяч человек в месяц (если верить статистике моего хостера).

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

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

P.S. Нашёл фото где я спрашиваю Вадима когда «Опера» будет поддерживать дробные проценты.

10 комментариев

PHP, UTF-8, всё ещё строки: упрощаем задачу, часть I

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

Что же дальше?
Выделив типичные случаи использования, частые и простые можно заменить автоматом, редкие и сложные — просто руками. Первым делом было бы неплохо узнать каково общее количество строк, с которыми мне придётся работать:

bolk@dev:~/daproject$ find \( -name '*.php' -or -name '*.inc' -or -name '*.tpl' \) -exec \
egrep '\$\{?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*[\[\{]' -- {} \; |
sort -u | tee out-vars-1.log | wc -l

3670

Около 3,5 тысяч. Я временами дьявольски усидчив, но рассматривать каждую строку из нескольких тысяч, это для меня перебор. Что же делать?

Для начала мне хочется упростить своё регулярное выражение. Конечно, по синтаксису PHP имена переменных можно писать, например, по-русски (в UTF-8), но в реальности, у меня имён, которые содержат не только цифры и латинские буквы, только шестнадцать (в этом я убедился, сделав «egrep -v ’\$\{?\w+’ out-vars.log | wc -l») и все эти строки содержат ерунду — совпадение внутри строк в апострофах, поэтому я с чистым сердцем выбрасываю все такие строки и упрощаю себе жизнь.

Безусловно, моё регулярное выражение захватило очень много лишнего, надо эти ситуации обработать. Например, можно исключить добавление элемента в массив, это легко узнаваемая конструкция ($arr[] = $elm):

bolk@wiki:~/daproject$ IFS='\n'
for line in $(cat out-vars-1.log); do
(echo $line | sed -r 's/\$\w+\[\]//g' | egrep -q '\$\{?\w+[\[\{]') && echo $line
done | sed -r 's/^\s+//' | awk '!t[$0]++' | tee out-vars-2.log | wc -l

3357

Ситуация мало изменилась, давайте попробуем улучшить её значительно. Например, удалить все строки, где происходит только явное обращение к массиву: $arr[’index’] (но не $arr[’index’][0]):

bolk@dev:~/daproject$ IFS='\n'
for line in $(cat out-vars-2.log); do
(echo $line | sed -r 's/\$\w+[\[\{](["'\''])[^\1]*\1(\]|\})([^\[\{])/\2/g' | egrep -q '\$\{?\w+[\[\{]') && echo $line
done | tee out-vars-3.log | wc -l

1353

Ощутимая разница. Открываем получившийся файл и смотрим что бы мы ещё могли выкинуть…

Продолжение следует, я сегодня рано встал, пойду домой.

Оставить комментарий

Бьёрн Страуструп в России

Мужчина в белой рубашке и светлых брюках сидит на стуле у деревянного стола с ноутбуком и микрофоном на сцене, готовясь к выступлению или презентации.
Бьёрн Страуструп

Вернулся с семинара, было интересно, но организация — полный кошмар. Официальное начало в 8:30, Бьёрн получил доступ к микрофону примерно в 10, поесть было негде, за исключением крошечного, сразу забившегося буфета, микрофоны желающим задать вопрос приносили с большим опозданием или вообще не приносили, ноутбук для демонстраций слайдов несколько раз «залипал».

Но самое главное — синхронный перевод. О, я получил удовольствие. Избранные фразы из моего твиттера:

Переводчик на семинаре Страуструпа несёт такой бред,что я не знаю что интереснее — смысл доклада или горячный бред в наушнике.

Переводчик: «когда мы своппируем поинтеры…»

Ещё: «для начала я тайпирую аллокаторы…»

Бьёрн рассказывает про сборщик мусора (garbage collector), переводчик долго молчит, потом: «тут у нас никакого мусора».

«Что касается магнитуды… величины фолт толерантности» — бубнит в наушник переводчик.

«Чё-то по поводу исключений… ля-ля, тополя». Ну, переводчик в ударе.

«У нас есть сингллинкед и анордеред массивы»,.. Даль вертится в гробу.

Бьёрн: «ок…», заметьте насколько переводчик более поэтичен: «да, давайте я соберусь с мыслями».

Переводчик переводит вопрос из зала: «ваша революция была давно, а родите нам ещё чё-нить, до того как умрёте».

Бьёрн (компьютер со слайдами опять сломался): «I don’t belive it», переводчик: «какого х…»

Бьёрн: «I think so…», переводчик, сквозь зевоту: «ага, щас попробую врубиться»

Переводчик, в сердцах: «о чём речь, вообще?!»

16 комментариев

Бьёрн Страуструп

Иду на семинар Бьёрна Страуструпа (это автор Си++ и первый «компьютерный учёный»). Жестокий мир — начало в 7:30! В интернете никого нет, вы что, спите все что ли?

15 комментариев

Мощь SVG и media queries

Вадим Макеев демонстрирует сейчас на фестивале «404» мощь SVG — картинка сама (через CSS media queries) изменяется для разных разрешений экрана, при масштабировании полноценное лого с текстом ужимается, текст сначала переносится, потом исчезает и остаётся один логотип.

Ребята, о таком применении SVG я даже и не думал, это очень круто.

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

Дополнено позднее: Вадим выложил слайды своего доклада (смотреть надо в «Опере»).

16 комментариев

PHP, UTF-8, рассуждения по поводу строк

Тёмная материя (18.16КиБ)

Работаю с низким приоритетом над автоматической заменой операций получения символа в строке по индексу на такую же операцию, но которая умела бы работать с UTF-8. Оказалось, что задача очень сложная.

Что дальше?
Во-первых, нужно учесть, что в PHP для способа получить символ по индексу — это квадратные скобки (\$str[0]) и фигурные ($str{0}). Причём, если мы встречаем фигурные скобки, то это точно строка, если мы встречаем фигурные, это может быть массив. Различать массив и строку в контексте абстрактных квадратных скобок, без полной интерпретации, невозможно. К счастью, мне это и не нужно, мой статический метод (я его назвал UTF::get(…)), проверяет является ли аргумент массивом и, если да, работает с ним как с массивом.

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

В-третьих, индексы могут идти подряд, например, $arr[0][2]{3}. Надо не забывать об этом и брать выражение целиком.

В-четвёртых, внутри индекса может идти любое годное PHP выражение, в том числе, внутри так же может быть операция взятия символа по индексу. Например: $str[1 + $str[0] + sin($arr[$a])].

В-пятых, есть переменные переменные, к примеру: $$$$$var[1], их тоже надо уметь обрабатывать, кроме того, они могут быть взяты в фигурные скобки, а в скобках могут быть вызовы функций, методов, имена переменных: ${$$$$var[1]}, ${$this->my()}{1}, ${str}{0}.

В-шестых, в PHP в строках опеределённого типа (в кавычках и heredoc) переменные интерполируются, в том числе интерполируются строковые переменные с получением символа по индексу, а кроме этого эти переменные могут быть в фигурных скобках: «{$aaa[1]} и можно ещё так: ${aaa[1]}», тут же надо не забывать, что переменные могут экранироваться, вот так: «\${aaa[1]}».

В общем, задача сложная, я над ней думаю. Пока в сторону парсеров синтаксиса (colorer, Text_Highlighter и PHP tokinizer). Из исследования выяснилось, что все они могут мне помочь примерно в равной степени, так что я думаю, что возьму PHP tokinizer.

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

5 комментариев

Огрызки от собеседований

От собеседований, которые я недавно проводил, у меня осталась масса листочков с заковыристыми вопросами. Например, если человек говорил, что знает PHP на 10 из 10, то я ему давал, например, такой тест:

var_dump((bool) print_r(${strrev('SLABOLG')} = 1, $GLOBALS[1]{1} == (unset) b"1") == "00");

Сказать есть ли тут ошибки, если нет, то что получим и что вообще тут происходит.

P.S. Я в Самаре, «Holiday Inn» отличный отель.

18 комментариев

← 1 44 45 46 47 48 67 →