unsetting an item in array has broken logic to ite

2019-02-27 19:10发布

问题:

I have the following logic inside my controller:

public function showvlans()
{
    $vlans=$this->switches_model->show_known_vlans($this->uri->segment(5), $this->uri->segment(4));
    //filter out VLAN 1 if its included in the list. 
    $key = array_search('1', $vlans);
    unset($vlans[$key]);
    header ('Content-Type: application/json; charset=UTF-8');
    echo json_encode($vlans);  

} // end showvlans  

For some reason, after I filter out a record from the array, my logic to loop through the json data is no longer working.

Here's the logic to loop through the json data:

alert(returnDataFromController.length);
//loop through results
for(i = 0; i < returnDataFromController.length; i++) {
    alert(returnDataFromController[i].VlanId);
    htmlstring = htmlstring +  "<tr><td><a href=>"+returnDataFromController[i].VlanId+"</a></td><td>"+ returnDataFromController[i].Name+"</td></tr>";                         
}

Clues:

The alert says "undefined".
I also dumped the data before and after removing the record from the array and here's what the json data looks like:

BEFORE REMOVING RECORD:

[09:36:52.986] [
    {VlanId:"1", Name:"VLAN1", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"3", Name:"VLAN3", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"8", Name:"VLAN8", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"16", Name:"VLAN16", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"20", Name:"VLAN20", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"33", Name:"VLAN33", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"64", Name:"VLAN64", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"65", Name:"VLAN65", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"66", Name:"VLAN66", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"80", Name:"VLAN80", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"96", Name:"VLAN96", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"101", Name:"VLAN101", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"128", Name:"VLAN128", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"131", Name:"VLAN131", Status:"Port-based", Voice:"No", Jumbo:"No"},
    {VlanId:"417", Name:"VLAN417", Status:"Port-based", Voice:"No", Jumbo:"No"}]

AFTER:

[09:34:41.797] (
    {1:{VlanId:"3", Name:"VLAN3", Status:"Port-based", Voice:"No", Jumbo:"No"},
     2:{VlanId:"8", Name:"VLAN8", Status:"Port-based", Voice:"No", Jumbo:"No"},
     3:{VlanId:"16", Name:"VLAN16", Status:"Port-based", Voice:"No", Jumbo:"No"},
     4:{VlanId:"20", Name:"VLAN20", Status:"Port-based", Voice:"No", Jumbo:"No"},
     5:{VlanId:"33", Name:"VLAN33", Status:"Port-based", Voice:"No", Jumbo:"No"},
     6:{VlanId:"64", Name:"VLAN64", Status:"Port-based", Voice:"No", Jumbo:"No"},
     7:{VlanId:"65", Name:"VLAN65", Status:"Port-based", Voice:"No", Jumbo:"No"},
     8:{VlanId:"66", Name:"VLAN66", Status:"Port-based", Voice:"No", Jumbo:"No"},
     9:{VlanId:"80", Name:"VLAN80", Status:"Port-based", Voice:"No", Jumbo:"No"},
     10:{VlanId:"96", Name:"VLAN96", Status:"Port-based", Voice:"No", Jumbo:"No"},
     11:{VlanId:"101", Name:"VLAN101", Status:"Port-based", Voice:"No", Jumbo:"No"},
     12:{VlanId:"128", Name:"VLAN128", Status:"Port-based", Voice:"No", Jumbo:"No"},
     13:{VlanId:"131", Name:"VLAN131", Status:"Port-based", Voice:"No", Jumbo:"No"},
     14:{VlanId:"417", Name:"VLAN417", Status:"Port-based", Voice:"No", Jumbo:"No"}})

As you can see, it does looks slightly different. I have an opening [ before I use the unset, whereas after I have (. I tried to change my loop control so that the variable i starts at 1 instead... but that didn't work either.

So for example, I tried the following:

for(i = 1; i < returnDataFromController.length; i++) {

instead of

for(i = 0; i < returnDataFromController.length; i++) {

回答1:

Let's say your array starts with 5 items. When all 5 items are present, the array keys are: 0, 1, 2, 3, 4

json_encode properly detects this as an enumerated array, and converts it to a JSON array.

However, let's say you remove the item at index 2. Now, you have: 0, 1, 3, 4. json_encode sees a non-sequential numbering of keys and now assumes it's an associative array, so you get back a JSON object with the keys 0, 1, 3, 4. Objects in JSON/Javascript don't have a length, so your code no longer works.

The trick is to use array_values before passing it to json_encode, if you want to enumerate it as an array.

Alternatively, you can change your for loop in JavaScript to:

for (var i in returnDataFromController) {
    if (returnDataFromController.hasOwnProperty(i)) {
        /* your code here */
    }
}

Although it is highly recommended to convert it to an array via array_values



回答2:

Javascript/JSON distinguishes between objects and arrays. Objects are key-value pairs using the { } syntax, arrays are numerically indexed lists using [ ].

When json_encodeing a PHP array, only arrays with continuous numeric indexes will be encoded to JSON/Javascript arrays, otherwise they'll become objects. E.g.:

array('foo', 'bar', 'baz')    -> ["foo", "bar", "baz"]
array(0 => 'foo', 2 => 'bar') -> {"0":"foo", "2":"bar"} 

To make sure your arrays have continuous numeric indexes, use array_values.