panoply
panoply

Reputation: 87

Error – Cannot traverse an already closed generator

I ran into this error today and sort of lost as to how to deal with it.

My app is grabbing data from an API and with that data, I query my database, get required data, create new value and send it back to API to update.

I have done some googling but still getting the hang of MVC and laravel, nothing I have read I could get to work with my code:

// Create Connection
$client = new Name\App(
      env('DOMAIN'),
      env('API_KEY'),
      env('PASSWORD'),
      env('SECRET')
    );

    //Get data from API
    $something = $client->getSomething('something');

    // Make empty Array
    $arr = [];

    // loop through data from API and create array of required data
    foreach ($something as $thing) {
      $arr[] = array('colors' => $thing->color);
    }

    // query database for values found from API array
    $eg = DB::table('table')
    ->select('eg','size', 'weight')
    ->whereIn('eg', $arr) // whereIn to query array
    ->get();

    // create another blank array
    $data = [];

    // loop the above query 
    foreach ($eg as $type) {

      // create json value to send back to api 
      // and update
      $data[] = [
        'mindfull' => [
          'this' =>  $type->en,
          'that' =>  $type->tva
        ]
      ];
    }

    // update API (this gives me the traverse generator error)
    foreach ($something as $again) {
      $client->put('link/' . $again->id, $data);
    }
  }

Any Ideas would be helpful.

Upvotes: 2

Views: 11328

Answers (2)

Oktokolo
Oktokolo

Reputation: 181

Like the commentor below alepino's answer mentioned, casting $something = $client->getSomething('something'); to array by using $something = iterator_to_array($something); before the first foreach loop, solves the asker's problem.

But in case someone else stumbles over "Cannot traverse an already closed generator" when trying to use iterator_to_array on a potentially exhausted iterator:
In PHP, generated Iterators (created by calling a function wich contains the yield keyword) can only be traversed until exhausted. Trying to get elements from them after exhaustion raises an Exception with mentioned message.

To safely convert a potentially exhausted Iterator to a potentially empty array, use
$a = $iter->valid() ? iterator_to_array($iter) : [];

Upvotes: 7

alepeino
alepeino

Reputation: 9771

This adds another iteration to your algorithm, but I guess this has to work:

Replace

//Get data from API
$something = $client->getSomething('something');

with

//Get data from API
$something = []
foreach ($client->getSomething('something') as $thing)
   $something []= $thing;

This way, the original generator is iterated only once. After that you have your array with the data.

Upvotes: 1

Related Questions