Use PHP functions in JavaScript

JavaScript each

Return the currently pointed key..value pair in the passed array, and advance the pointer to the next element

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
function each (arr) {
    // Return the currently pointed key..value pair in the passed array, and advance the pointer to the next element  
    // 
    // version: 1001.2911
    // discuss at: http://phpjs.org/functions/each    // +   original by: Ates Goral (http://magnetiq.com) 
    // +    revised by: Brett Zamir (http://brett-zamir.me)
    // %        note 1: Uses global: php_js to store the array pointer
    // *     example 1: each({a: "apple", b: "balloon"});
    // *     returns 1: {0: "a", 1: "apple", key: "a", value: "apple"}    //  Will return a 4-item object unless a class property 'returnArrayOnly'
    //  is set to true on this function if want to only receive a two-item
    //  numerically-indexed array (for the sake of array destructuring in
    //  JavaScript 1.7+ (similar to list() in PHP, but as PHP does it automatically
    //  in that context and JavaScript cannot, we needed something to allow that option)    //  See https://developer.mozilla.org/en/New_in_JavaScript_1.7#Destructuring_assignment
    
    // BEGIN REDUNDANT
    this.php_js = this.php_js || {};
    this.php_js.pointers = this.php_js.pointers || [];        var indexOf = function (value) {
        for (var i = 0, length=this.length; i < length; i++) {
            if (this[i] === value) {
                return i;
            }        }
        return -1;
    };
    // END REDUNDANT
    var pointers = this.php_js.pointers;        if (!pointers.indexOf) {
        pointers.indexOf = indexOf;
    }
    if (pointers.indexOf(arr) === -1) {
        pointers.push(arr, 0);    }
    var arrpos = pointers.indexOf(arr);
    var cursor = pointers[arrpos+1];
    var pos = 0;
     if (!(arr instanceof Array)) {
        var ct = 0;
        for (var k in arr) {
            if (ct === cursor) {
                pointers[arrpos+1] += 1;                if (each.returnArrayOnly) {
                    return [k, arr[k]];
                } else {
                    return {
                        1:arr[k],                        value:arr[k],
                        0:k,
                        key:k
                    };
                }            }
            ct++;
        }
        return false; // Empty
    }    if (arr.length === 0 || cursor === arr.length) {
        return false;
    }
    pos = cursor;
    pointers[arrpos+1] += 1;    if (each.returnArrayOnly) {
        return [pos, arr[pos]];
    } else {
        return {
            1:arr[pos],            value:arr[pos],
            0:pos,
            key:pos
        };
    }}
external links: original PHP docs | raw js source

Examples

Running

1
each({a: "apple", b: "balloon"});

Should return

1
{0: "a", 1: "apple", key: "a", value: "apple"}

Dependencies

No dependencies, you can use this function standalone.

Open syntax issues

php.js uses JsLint to help us keep our code consistent and prevent some common bugs.

Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.


Authors

Thanks to the following developers, you get to have each goodness in JavaScript.

Comments

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
Kevin van Zonneveld
6 Jan '09 Permalink

q  @ Brett Zamir: Nice dude :)

Gravatar
Brett Zamir
1 Jan '09 Permalink

q  By the way, I noticed now that there is a built-in way in JavaScript 1.7 to do the each() iteration: using Iterator() (and otherwise progress through arrays/objects). See https://developer.mozilla.org/en/New_in_JavaScript_1.7#Looping_across_objects and https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Iterators_and_Generators#Iterators

Still, it shouldn't hurt to have them with the PHP equivalents (I think the PHP way is easier)...

Brett

Gravatar
Brett Zamir
1 Jan '09 Permalink

q   Hi Kevin,

I think I got it working now...

Thanks for the offer... Although I don't drink (I'm a Baha'i), if I did drink, I'd be glad to have one with you... You seem like a most gracious person... Have a happy new year... And Onno too--thanks for keeping me on my toes, you guys... :)

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
152
153
154
155156
157
158
159
160161
162
163
164
165166
167
168
169
170171
172
173
174
175176
177
178
179
180181
182
183
function pos (arr) { // Alias of current
  return current(arr);
}
function current (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var arrpos = pointers.indexOf(arr);  var cursor = pointers[arrpos+1];
  if (arr instanceof Array) {
    return arr[cursor] || false;
  }
  var ct = 0;  for (var k in arr) {
    if (ct === cursor) {
      return arr[k];
    }
    ct++;  }
  return false; // Empty
}
function next (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var arrpos = pointers.indexOf(arr);  var cursor = pointers[arrpos+1];
  if (!(arr instanceof Array)) {
    var ct = 0;
    for (var k in arr) {
      if (ct === cursor+1) {        pointers[arrpos+1] += 1;
        return arr[k];
      }
      ct++;
    }    return false; // End
  }
  if (arr.length === 0 || cursor === (arr.length-1)) {
      return false;
  }  pointers[arrpos+1] += 1;
  return arr[pointers[arrpos+1]];
}
function prev (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  var arrpos = pointers.indexOf(arr);
  var cursor = pointers[arrpos+1];
  if (pointers.indexOf(arr) === -1 || cursor === 0) {
    return false;  }
  if (!(arr instanceof Array)) {
    var ct = 0;
    for (var k in arr) {
      if (ct === cursor-1) {        pointers[arrpos+1] -= 1;
        return arr[k];
      }
      ct++;
    }    // Shouldn't reach here
  }
  if (arr.length === 0) {
    return false;
  }  pointers[arrpos+1] -= 1;
  return arr[pointers[arrpos+1]];
}
function reset (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var arrpos = pointers.indexOf(arr);  if (!(arr instanceof Array)) {
    for (var k in arr) {
      if (pointers.indexOf(arr) === -1) {
       pointers.push(arr, 0);
      }      else {
        pointers[arrpos+1] = 0;
      }
      return arr[k];
    }    return false; // Empty
  }
  if (arr.length === 0) {
    return false;
  }  pointers[arrpos+1] = 0;
  return arr[pointers[arrpos+1]];
}
function end (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var arrpos = pointers.indexOf(arr);  if (!(arr instanceof Array)) {
    var ct = 0;
    for (var k in arr) {
      ct++;
      var val = arr[k];    }
    if (ct === 0) {
      return false; // Empty
    }
    pointers[arrpos+1] = ct - 1;    return val;
  }
  if (arr.length === 0) {
    return false;
  }  pointers[arrpos+1] = arr.length - 1;
  return arr[pointers[arrpos+1]];
}
function key (arr) {
  if (!window.php_js) window.php_js = {pointers:[]};  var pointers = window.php_js.pointers;
  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var cursor = pointers[pointers.indexOf(arr)+1];  if (!(arr instanceof Array)) {
    var ct = 0;
    for (var k in arr) {
      if (ct === cursor) {
        return k;      }
      ct++;
    }
    return false; // Empty
  }  if (arr.length === 0) {
    return false;
  }
  return cursor;
}function each (arr) {
  // Will return a 4-item object unless a class property 'returnArrayOnly' is set to true on this function if want to only receive a two-item numerically-indexed array (for the sake of array destructuring in JavaScript 1.7+ (similar to list() in PHP, but as PHP does it automatically in that context and JavaScript cannot, we needed something to allow that option)
  //   See https://developer.mozilla.org/en/New_in_JavaScript_1.7#Destructuring_assignment
  if (!window.php_js) window.php_js = {pointers:[]};
  var pointers = window.php_js.pointers;  if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, 0);
  }
  var arrpos = pointers.indexOf(arr);
  var cursor = pointers[arrpos+1];  if (!(arr instanceof Array)) {
    var ct = 0;
    for (var k in arr) {
      if (ct === cursor) {
        pointers[arrpos+1] += 1;        if (each.returnArrayOnly) {
          return [k, arr[k]];  
        }
        else {
          return {1:arr[k], value:arr[k], 0:k, key:k};        }
      }
      ct++;
    }
    return false; // Empty  }
  if (arr.length === 0 || cursor === arr.length) {
    return false;
  }
  pos = cursor;  pointers[arrpos+1] += 1;
  if (each.returnArrayOnly) {
    return [pos, arr[pos]];  
  }
  else {    return {1:arr[pos], value:arr[pos], 0:pos, key:pos};
  }
}

Gravatar
Kevin van Zonneveld
31 Dec '08 Permalink

q  @ Brett Zamir: You're onto something there! I'm sure we'll work it out next year ;) Guys, best wishes and have a good one tonight. Have a drink from me will you?

And let 2009 be a happy & successful year for you & your projects :) Regards!

Gravatar
Brett Zamir
30 Dec '08 Permalink

q   Yeah, that's a good point about serialization.

Since we can't get unique memory addresses directly in JavaScript (thank heavens!) (and toSource() as an id would not distinguish between arrays with the same values), I think what we might try is to store their references directly (for the sake of later comparison) like this along with the key:

1
2
3
4
56
7
var pointers = window.php_js.pointers;
if (pointers.indexOf(arr) === -1) {
    pointers.push(arr, incrementVal);
}
else {    pointers[pointers.indexOf(arr)+1] += incrementVal; // Or do whatever needed to be done
}


I'll try to look into that later (unless you're so inspired), as well as get back to you on the constants function... All the best...

Gravatar
Kevin van Zonneveld
30 Dec '08 Permalink

q   @ Brett Zamir: That's some hard labour there Brett. And it makes me smile that with these functions you could actually do this:

1
2
3
4
reset($fruit);
while ([$key, $val] = each($fruit)) {
    echo ($key +&quot;:&quot;+ $val+&quot;\n&quot;);
}

In JavaScript :) So kuddo's to you man.

But (sorry, there always is a but) before adding, I do not feel comfortable storing the pointer inside the userobject. This may introduce the infamous Heisenbug.

Imagine you have an important object that stores user information. You work on it using reset & each (you do not expect these to alter your data in any way), serialize it, and finally send it to the server.
Now the serialized information will contain a strange element: '_phpjs_pos' that may lead to all kind of unexpected results. It may cause unaware developers some hard time debugging, and may (in some rare cases but still) even lead to server side data corruption. In short, this is not something I can willingly introduce to the project.

I'd rather it be stored in the window.php_js global variable, as we already have such a mechanism for include_once. So we're not introducing additional dirt.

I imagine something like:
1
window.php_js.pointers[pointerId] = key;


One challenge of that approach is that we'd have to figure out a way to add the scope to the so-called pointerId. But if we cannot overcome that I have some strong issues with adding these current implementations.

Can you guys share this opinion?

Gravatar
Brett Zamir
20 Dec '08 Permalink

q   While the above functioning works fine from what I can tell (besides not offering to return a regular array in circumstances as is useful with destructuring assignment in JavaScript 1.7), in order to maintain pointer state in a way which would work across all such functions (and also make the array key a little more "namespaced"), I rewrote each() as well as added all of the following functions. I hadn't thought about using a property on the array to preserve the pointer position until now, so I was mistaken in thinking it not possible to do this in JavaScript.

...Examples are adapted from the PHP manual...Note that the pointer property is not reset by other JavaScript actions as it might be in PHP (e.g., assigning an array to another variable).



1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
152
153
154
155156
157
158
159
160161
162
163
164
165166
167
168
169
170171
172
173
174
175176
177
178
179
180181
182
183
184
185186
187
188
189
$foo = {&quot;Robert&quot; : &quot;Bob&quot;, &quot;Seppo&quot; : &quot;Sepi&quot;};
$bar = each($foo);
var_dump($bar)
 
$fruit = {'a' : 'apple', 'b' : 'banana', 'c' : 'cranberry'}; 
reset($fruit);
while ([$key, $val] = each($fruit)) {
    alert( $key +&quot;:&quot;+ $val+&quot;\n&quot;);
} 
 
$transport = new Array('foot', 'bike', 'car', 'plane');
// $transport = {a:2, b:3}; // Tried also with this
$mode = current($transport); // $mode = 'foot';$mode = next($transport);    // $mode = 'bike';
$mode = current($transport); // $mode = 'bike';
$mode = prev($transport);    // $mode = 'foot';
$mode = end($transport);     // $mode = 'plane';
$mode = current($transport); // $mode = 'plane'; 
$arr = [];
var_dump(current($arr)); // bool(false)
 
$arr = new Array([]);var_dump(current($arr)); // array(0) { }
 
 
function pos (arr) { // Alias of current
        return current(arr);}
function current (arr) {
        if (!arr._phpjs_pos) {
                arr._phpjs_pos = 0;
        }        if (arr instanceof Array) {
                return arr[arr._phpjs_pos] || false;
        }
        var ct = 0;
        for (var k in arr) {                if (k !== '_phpjs_pos') {
                        if (ct === arr._phpjs_pos) {
                                return arr[k];
                        }
                        ct++;                }
        }
        return false; // Empty
}
function next (arr) {        if (!arr._phpjs_pos) {
        arr._phpjs_pos = 0;
    }
        if (!(arr instanceof Array)) {
                var ct = 0;                for (var k in arr) {
                        if (k !== '_phpjs_pos') {
                                if (ct === arr._phpjs_pos+1) {
                                        arr._phpjs_pos += 1;
                                        return arr[k];                                }
                                ct++;
                        }
                }
                return false; // End        }
    if (arr.length === 0 || arr._phpjs_pos === (arr.length-1)) {
        return false;
    }
    arr._phpjs_pos += 1;    return arr[arr._phpjs_pos];
}
function prev (arr) {
        if (arr._phpjs_pos === 0 || arr._phpjs_pos === undefined) {
                return false;        }
        if (!(arr instanceof Array)) {
                var ct = 0;
                for (var k in arr) {
                        if (k !== '_phpjs_pos') {                                if (ct === arr._phpjs_pos-1) {
                                        arr._phpjs_pos -= 1;
                                        return arr[k];
                                }
                                ct++;                        }
                }
                // Shouldn't reach here
        }
        if (arr.length === 0) {        return false;
    }
    arr._phpjs_pos -= 1;
    return arr[arr._phpjs_pos];
}function reset (arr) {
        if (!(arr instanceof Array)) {
                for (var k in arr) {
                        if (k !== '_phpjs_pos') {
                                arr._phpjs_pos = 0;                                return arr[k];
                        }
                }
                return false; // Empty
        }        if (arr.length === 0) {
                return false;
        }
        arr._phpjs_pos = 0;
    return arr[arr._phpjs_pos];}
function end (arr) {
        if (!(arr instanceof Array)) {
                var ct = 0;
                for (var k in arr) {                        if (k !== '_phpjs_pos') {
                                ct++;
                                var val = arr[k];
                        }
                }                if (ct === 0) {
                        return false; // Empty
                }
                arr._phpjs_pos = ct - 1;
                return val;        }
        if (arr.length === 0) {
                return false;
        }
        arr._phpjs_pos = arr.length - 1;    return arr[arr._phpjs_pos];
}
function key (arr) {
        if (!arr._phpjs_pos) {
                arr._phpjs_pos = 0;        }
        if (!(arr instanceof Array)) {
                var ct = 0;
                for (var k in arr) {
                        if (k !== '_phpjs_pos') {                                if (ct === arr._phpjs_pos) {
                                        return k;
                                }
                                ct++;
                        }                }
                return false; // Empty
        }
        if (arr.length === 0) { // Todo: verify this is result (and return false just above)
                return false;        }
        return arr._phpjs_pos !== undefined ? arr._phpjs_pos : 0;
}
function each (arr) {
        // Will return a 4-item object unless a class property 'returnArrayOnly' is set to true on this function if want to only receive a two-item numerically-indexed array (for the sake of array destructuring in JavaScript 1.7+ (similar to list() in PHP, but as PHP does it automatically in that context and JavaScript cannot, we needed something to allow that option)        //      See https://developer.mozilla.org/en/New_in_JavaScript_1.7#Destructuring_assignment
        if (!arr._phpjs_pos) {
                arr._phpjs_pos = 0;
        }
        if (!(arr instanceof Array)) {                var ct = 0;
                for (var k in arr) {
                        if (k !== '_phpjs_pos') {
                                if (ct === arr._phpjs_pos) {
                                        arr._phpjs_pos += 1;                                        if (each.returnArrayOnly) {
                                                return [k, arr[k]];     
                                        }
                                        else {
                                                return {1:arr[k], value:arr[k], 0:k, key:k};                                        }
                                }
                                ct++;
                        }
                }                return false; // Empty
        }
        if (arr.length === 0 || arr._phpjs_pos === arr.length) {
                return false;
        }        pos = arr._phpjs_pos;
        arr._phpjs_pos += 1;
        if (each.returnArrayOnly) {
                return [pos, arr[pos]]; 
        }        else {
                return {1:arr[pos], value:arr[pos], 0:pos, key:pos};
        }
}


Contribute a New function