пятница, 4 октября 2013 г.

php, мелкие трюки, передача параметров в функцию, и php-шники

Решал тут небольшую задачу на php.

Я его, в руки не брал давненько, многое подзабыл, да и так -  в целом, не мой любимый инструмент.

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

Задача сама банальна. И говорить там не о чём, ну разве что один трюк.

Как все мы знаем, php рожден что б умирать (http://habrahabr.ru/post/179399/), это понятная концепция , но она вносит интересные коррективы.
Если вы запускаете свой код под веб браузером, то скорее всего на вас повлияет max execution time. Время, после которого скрипт будет убит принудительно.

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

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

$stmt->execute(); // Финальная вставка записи в базу
$time_end = micro_time(); //Текущее время
$execution_time = $time_end - $time_start; // стартовое  время записали при старте
$inserted=$count-$skip;
if($execution_time>$time_to_run) {
    echo "<html><head><meta http-equiv='refresh' content='$time_to_wait; URL=$script?skip=$count'></head><body>Inserted :  $inserted, Time : $execution_time</body><html>";
    die;
    //Умираем сделав вызов себя с параметром через браузер
}

Ну, и вторая тонкость, в нынешнем мире все любят DOM, он прост, красив, и селекторы его прекрасны.
Но что делать если вам нужно обрабатывать xml в сотни мегабайт, на слабеньком VDS?

Конечно же http://ru.wikipedia.org/wiki/SAX

    $xml_parser = xml_parser_create();
    xml_set_element_handler($xml_parser, "startElement", "endElement");
    xml_set_character_data_handler($xml_parser, "contents");
    if (!($fp = fopen($file, "r"))) {
        die("Невозможно произвести чтение XML $file");
    }
    while ($data = fread($fp, 4096)) {
        if (!xml_parse($xml_parser, $data, feof($fp))) {
            die(sprintf("Ошибка XML: %s на строке %d",
                xml_error_string(xml_get_error_code($xml_parser)),
                xml_get_current_line_number($xml_parser)));
        }
    }
    xml_parser_free($xml_parser);

Парсит быстро и приятно.


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

Есть функция с произвольным количеством аргументов, я хочу передать в нее массив аргументов.
Ну, как у нормальных людей sub(@a);
В пхп для этого есть специальная функция, call_user_func_array, как вам?

Ну т.е. у них нормально писать такой код:

call_user_func_array('mysqli_stmt_bind_param', array_merge (array($stmt, $b_str), refValues($arr1)));

Прэлесть.

Кстати, знаете почему там, refValues вот такая вот


function refValues($arr){
        if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
        {
            $refs = array();
            foreach($arr as $key => $value)
                $refs[$key] = &$arr[$key];
            return $refs;
        }
        return $arr;
    }

используется?

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

Но это я бы пережил. Самое страшное не это.
Самое страшное это сами php-шники.

Я несколько раз по всяким мелочам заглядывал на php.net, ну как в справочник.

Все же знают что для php нормально что у пары обратных функций explode/implode будет разный порядок аргументов, а то и разное их количество.
Ну и не заставишь же живого человека это помнить.
Идешь на php.net, и там в комментах к каждой странице есть чятик.
Такой чятик, что прямо веру теряешь в константу разума на планете.

Там комменты, в стиле: а я забыл какая функция джойнит массивы поэтому вот мой код, и дальше страшное убожище где алгоритмом сложностью o(n^5) с помощью циклов и страшных переменных, что нить происходит.

Ни обработки ошибок, ни задумчивости о сложности и потреблении памяти, ничего.

И самой страшное, что потом идет 200 комментов, в стиле: да спасибо, очень помогло скопировал себе или
о, круто, а я скопировал, но заменил тут вот такую функцию на цикл вон из того коммента.
И в итоге просто месиво месиво, кровь кишки.

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

Я теперь понимаю откуда у php-ников такие листинги.
Ну пишешь на перле когда: 50 строк это уже большая программа, еще бы , у тебя ж весь cpan под руками, который больше может чем вся индия.
А в php, 5000 строк аццкого копипаста, это типа преамбулы идет.
Просто переменные подготовить. Массив там склеить, то се.

Очень рад я, что редко с чужим php кодом сталкиваюсь, но когда сталкиваюсь - стабильно удивляет.