PHP. Рекурсивная замена строк на числа занимает слишком много времени.

Поскольку «SELECT» MYSQL выбирает целые числа и плавает как строки, и мне нужен каждый ответ, который я получаю (от JS), чтобы быть в правильной модели данных –

  • 1 не «1»,
  • 53.2 не "53.2",

Я создал эту рекурсивную функцию, которая работает с смешанным типом-массивом / объектом:

private function cast_number(&$mixed) { if(is_array($mixed)) { foreach ($mixed as $key => $val) if (is_numeric($val)) $mixed[$key] = (double)$val; else if (is_array($val) || is_object($val)) $mixed[$key] = $this->cast_number($val); } else if(is_object($mixed)) { foreach ($mixed as $key => $val) if (is_numeric($val)) $mixed->$key = (double)$val; else if (is_array($val) || is_object($val)) $mixed->$key = $this->cast_number($val); } return $mixed; } 

Довольно простая функция – если это число, двойное, если массив или объект, переходите рекурсивно.

Все здесь на месте.

У меня есть две проблемы с этим: – На 6 Мбайтах данных, в основном числа, которые представлены в виде строк, потребовалось 0,5 секунды – на 200 МБ данных (да, мне это нужно, пожалуйста, не сосредотачивайтесь на нем), он не удался после пару минут (обычно секунд), говоря, что ему требуется более 4 ГБ памяти.

  1. Как я могу улучшить эту функцию? (Скорость, память)
  2. Почему это так долго? даже json_encode, что я думаю, что это большая функция, занимает гораздо меньше времени.

Поскольку принуждение использовалось быстрее, чем литье , я запускал этот код для вычисления таймингов на PHP 7:

 function getTime($start) { return round((microtime(true) - $start) * 1000000) / 1000; } function mockData($length) { $data = []; $i = -1; while ($i++ < $length) { $data[$i] = strval(rand(1, 10000) / 100); } return $data; } $data = mockData(100000); // Let's check that they are string before echo gettype($data[0]) . '<br><br>'; $start = microtime(true); $convertedData = []; foreach ($data as $key => $value) { $convertedData[$key] = (double) $value; } echo '(double) cast took ' . getTime($start) . ' ms.<br>'; $start = microtime(true); $convertedData = []; foreach ($data as $key => $value) { $convertedData[$key] = 0 + $value; } echo 'Coercion took ' . getTime($start) . ' ms.<br>'; 

И мои результаты:

 (double) cast took 27.508 ms. Coercion took 28.789 ms. 

ВЫВОД

Поскольку использование floatval (третий способ для преобразования строк в двойное преобразование) еще длиннее, вы не можете сделать лучше, чем с PHP. То, что вы пытаетесь достичь, – это сценарирование, оно не должно использоваться как обычная операционная система для веб-приложения.

Но если вы все еще хотите это сделать, вы можете memory_limit свой memory_limit внутри вашего файла php.ini , если вы не используете обходной путь -1 .

ОБНОВИТЬ

Я забыл одну возможную оптимизацию, вы должны передать свою переменную по ссылке, чтобы хотя бы выполнить немедленную переадресацию:

 $start = microtime(true); foreach ($data as $key => $value) { $data[$key] = (double) $value; } echo getTime($start) . ' ms.<br>'; 

=> 34,018 мс.

 $start = microtime(true); foreach ($data as &$value) { $value = (double) $value; } echo getTime($start) . ' ms.<br>'; 

=> 17.081 мс.

И, по-видимому, использование принуждения со ссылкой дает еще лучшие результаты:

 $start = microtime(true); foreach ($data as &$value) { $value = 0 + $value; } echo getTime($start) . ' ms.<br>'; 

=> 13,1 мс.

Это должно улучшить скорость и память:

 private function cast_number(&$mixed) { foreach ($mixed as &$val) { if (is_numeric($val)) { $val = (double) $val; } else if (is_array($val) || is_object($val)) { $this->cast_number($val); } } // do not return $mixed } 

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