Apache падает в большом цикле foreach на ассоциативном массиве в PHP - PullRequest
3 голосов
/ 17 апреля 2011

РЕДАКТИРОВАТЬ : В ответ на ответ Робуса я попытался запустить скрипт PHP из командной строки. Это результат:

CLI crash

Но интересно; оператор echo, который был расположен после цикла foreach в моем коде, выводит его текст в окно консоли. Таким образом, я могу только предположить, что CLI падает после завершения / после запуска скрипта.


У меня есть скрипт, функция которого заключается в загрузке всех строк из файла XLSX в таблицу MySQL. Я использую PHPExcel для этого. Я написал функцию loadFromXLS для загрузки данных из файла XLSX и возврата двумерного массива с данными. В данном конкретном случае это означает 3100 строк и 29 столбцов.

Это функция:

function loadFromXLS($filepath)
{
    $retval = array();
    $cols = array();
    $rownum = 0;

    $reader = PHPExcel_IOFactory::createReaderForFile($filepath);
    $reader->setReadDataOnly(true);

    $phpObject = $reader->load($filepath);
    $sheet = $phpObject->getActiveSheet();

    foreach($sheet->getRowIterator() as $row)
    {
        $celliterator = $row->getCellIterator();
        $celliterator->setIterateOnlyExistingCells(false);
        $cellnum = 0;

        foreach($celliterator as $cell)
        {
            if($rownum === 0)
            {
                $cols[$cellnum] = $cell->getValue();
            }
            else
            {
                if(is_array($retval[$rownum-1]))
                    $retval[$rownum-1] += array($cols[$cellnum] => $cell->getValue());
                else
                    $retval[$rownum-1] = array($cols[$cellnum] => $cell->getValue());
            }

            $cellnum++;
        }

        $rownum++;
    }

    unset($reader, $phpObject, $sheet);

    return $retval;
}

Верхняя строка файла - это имена столбцов.

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

Это проблема. Как только я добавлю эту строку:

foreach($data as $i => $row) {};

Apache просто падает, когда доходит до этой точки:

Apache crash

Так что с этим? Не может ли PHP обрабатывать циклы через большие ассоциативные массивы? Любые объяснительные ответы будут оценены. Пожалуйста, прокомментируйте, если есть дополнительная информация, которую я могу предоставить


Я использую XAMPP на Windows 7, процессор Intel i5, 4 ГБ ОЗУ. Я увеличил memory_limit в php.ini до 512 МБ, что более чем достаточно (раньше я получал ошибку памяти, когда он был установлен на 128 МБ). Этот скрипт включает в себя PHPExcel.php и dBug.php. Двумерный массив заполнен только строками, а не типами типов PHPExcel.

Я использую PHP версии 5.3.1

нагруженных модулей: ядро ​​mod_win32 mpm_winnt http_core mod_so mod_actions mod_alias mod_asis mod_auth_basic mod_auth_digest mod_authn_default mod_authn_file mod_authz_default mod_authz_groupfile mod_authz_host mod_authz_user mod_cgi mod_dav mod_dav_fs mod_dav_lock mod_dir mod_env mod_headers mod_include mod_info mod_isapi mod_log_config mod_mime mod_negotiation mod_rewrite mod_setenvif mod_ssl mod_status mod_autoindex_color mod_php5 mod_perl mod_apreq2

phpinfo () снимок экрана

Ответы [ 4 ]

2 голосов
/ 17 апреля 2011

Попробуйте вообще пропустить apache и просто запустите скрипт из командной строки, посмотрите, что получится

1 голос
/ 17 апреля 2011

Обновите вашу установку php.

0 голосов
/ 18 апреля 2011

Простое удаление $ phpObject и $ sheet не даст никакого эффекта.Они содержат циклические ссылки на объекты, которые плохо очищаются в PHP, поэтому они не будут сброшены, если вы сначала не разорвете эти ссылки.Это можно сделать с помощью

$phpObject->disconnectWorksheets();

, как описано в разделе 4.3 документации разработчика («Очистка рабочей книги из памяти»).

Избавьтесь от циклов итераторов для заполнения вашего массива,и использовать встроенный метод PHPExcel.

return $sheet->toArray(); 

Вы также можете передать следующие аргументы методу toArray ():

* @param  mixed    $nullValue            Value returned in the array entry if a cell doesn't exist
* @param  boolean  $calculateFormulas    Should formulas be calculated?
* @param  boolean  $formatData           Should formatting be applied to cell values?
* @param  boolean  $returnCellRef        False - Return a simple array of rows and columns indexed by number counting from zero
*                                        True - Return rows and columns indexed by their actual row and column IDs

Это не даст вам достаточно ассоциативный массивто, что делают ваши собственные циклы, но это будет быстрее и эффективнее, чем ваши циклы.

0 голосов
/ 17 апреля 2011
  1. Добавьте немного памяти в PHP.

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

    function loadFromXLS($filepath,&$retval) {
      ...
    }
    

    Затем вы должны удалить $ retval = array (); и поставить его перед вызовом этой функции.

...