PHP не хватает памяти с помощью CDataProviderIterator (Yii)

У меня проблема с нехваткой памяти в моем PHP-скрипте на платформе Yii. Я пытался немного отладить. Я использую CDataProviderIterator, потому что в документации Yii об этом говорится:

Например, следующий код будет перебирать всех зарегистрированных пользователей (активный класс записей User) без нехватки памяти, даже если в базе данных миллионы пользователей.

Этот код перебирает около 1,5 миллиона записей, и при попытке ему не хватает памяти. Я ищу любую помощь, почему это может быть сделано. Спасибо!

public function foo($model, $relations) {
    $dataProvider = new CActiveDataProvider($model, array('criteria' => $model->dbCriteria));
    $iterator = new CDataProviderIterator($dataProvider, 200);
    $this->modelsToArray($iterator, $relations, $model_as_array = array());
}

public function modelsToArray($model, $relations, $model_as_array = array()) {
    $preparedRelations = $this->prepareRelations($relations);
    if (is_null($model))
    {
        return array();
    }
    $model_as_array = array();
    if (get_class($model) === 'CDataProviderIterator') {
        foreach ($model as $row) {
            $model_as_array[] = $this->modelsToArrayHelper($preparedRelations, $row);
        }   
    }
    else {
        $model_as_array[] = $this->modelsToArrayHelper($preparedRelations, $model);
    }

    return $model_as_array;
}

private function modelsToArrayHelper($relations, $listOfModels) {
    $listOfArrayModels = array();

    if(!is_array($listOfModels)){
        return $this->modelToArrayHelper($listOfModels, $relations);
    }
    foreach ($listOfModels as $index => $model)
    {
        $listOfArrayModels[$index] = $this->modelToArrayHelper($model, $relations);
    }
    return $listOfArrayModels;
}

private function modelToArrayHelper($model, $relations){
    $model_as_array = $this->processAttributes($model);
    foreach ($relations as $relationIndex => $relation)
    {
        $relationName = is_string($relationIndex) ? $relationIndex : $relation;
        if(empty($model->$relationName)) 
            continue;
        if ($model->relations()[$relationName][0] != CActiveRecord::STAT)
        {
            $subRelations = is_array($relation) ? $relation : array();
            $model_as_array[$relationName] = $this->modelsToArrayHelper($subRelations, $model->$relationName);
        }
        else
        {
            $model_as_array[$relationName] = $model->$relationName;
        }
    }

    return $model_as_array;
}

person Sloganho    schedule 15.04.2016    source источник
comment
быстрое исправление, пока я пытаюсь воссоздать этот ini_set('memory_limit', '-1');   -  person Midhun    schedule 15.04.2016
comment
вы конвертируете $iterator в массив, поэтому ему потребуется больше оперативной памяти! я думаю, что это вызывает проблему   -  person Midhun    schedule 15.04.2016
comment
ты решил это?   -  person Midhun    schedule 16.04.2016


Ответы (1)


я полагаю, вы пытаетесь преобразовать CDataProviderIterator в массив Php. поэтому для размещения массива нужно больше памяти

ini_set('memory_limit', '-1');

это устанавливает максимальное использование оперативной памяти

ini_set('memory_limit', '512M');

это устанавливает использование оперативной памяти на 512 МБ

Можете ли вы сделать свой код таким, чтобы убедиться, что вы не используете слишком много оперативной памяти?

public function foo($model, $relations) {
    $dataProvider = new CActiveDataProvider($model, array('criteria' => $model->dbCriteria));
    $iterator = new CDataProviderIterator($dataProvider, 200);
    $preparedRelations = $this->prepareRelations($relations);
    foreach ($iterator as $row) {
           print_r ($this->modelsToArrayHelper($preparedRelations, $row));
    }   
}

а также

person Midhun    schedule 15.04.2016
comment
Поэтому я не пытаюсь преобразовать CDataProviderIterator в массив php. Я преобразовываю каждую запись, которую он повторяет, в массив. На самом деле это должно сохранить память, потому что CDataProviderIterator не хранит все объекты в памяти. В моем случае он будет хранить в памяти только 200 объектов модели за раз, а затем удалит их. Я попробовал ваше решение, и теперь я просто не получаю ответа. Мой главный вопрос заключается в том, почему это занимает так много памяти, когда на самом деле должно занимать меньше памяти, основываясь на утверждениях в документации. - person Sloganho; 15.04.2016
comment
Потому что похоже, что вы пытаетесь хранить 1,5 миллиона массивов внутри $model_as_array. - person georaldc; 15.04.2016
comment
да, я это вижу, но что вы делаете с $model_as_array; - person Midhun; 15.04.2016
comment
Я пытаюсь сохранить 1,5 миллиона объектов внутри массива $model_as_array. Что я делаю с $model_as_array, так это конвертирую его в JSON и отправляю обратно клиенту. Установка такого ограничения памяти не кажется мне хорошей практикой. Я все равно попробовал, и это не сработало. Я нашел решение просто преобразовать массив в JSON по ходу дела, вызывая unset для объекта после его преобразования для сохранения памяти. Это работает и фактически сохраняет память, а не просто изменяет ограничение памяти. Спасибо за вашу помощь. - person Sloganho; 16.04.2016
comment
хорошо, можете ли вы поделиться образцом кода для своего решения, чтобы сообщество также могло извлечь выгоду. Пожалуйста, добавьте его в качестве ответа - person Midhun; 16.04.2016