Use PHP functions in JavaScript

JavaScript is_array

Returns true if variable is an array

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
function is_array (mixed_var) {
    // Returns true if variable is an array  
    // 
    // version: 1008.1718
    // discuss at: http://phpjs.org/functions/is_array    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Legaev Andrey
    // +   bugfixed by: Cord
    // +   bugfixed by: Manish
    // +   improved by: Onno Marsman    // +   improved by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // %        note 1: In php.js, javascript objects are like php associative arrays, thus JavaScript objects will also
    // %        note 1: return true  in this function (except for objects which inherit properties, being thus used as objects),
    // %        note 1: unless you do ini_set('phpjs.objectsAsArrays', true), in which case only genuine JavaScript arrays    // %        note 1: will return true
    // *     example 1: is_array(['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
    // *     example 2: is_array('Kevin van Zonneveld');
    // *     returns 2: false    // *     example 3: is_array({0: 'Kevin', 1: 'van', 2: 'Zonneveld'});
    // *     returns 3: true
    // *     example 4: is_array(function tmp_a(){this.name = 'Kevin'});
    // *     returns 4: false
    var key = '';    var getFuncName = function (fn) {
        var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
        if (!name) {
            return '(Anonymous)';
        }        return name[1];
    };
 
    if (!mixed_var) {
        return false;    }
 
    // BEGIN REDUNDANT
    this.php_js = this.php_js || {};
    this.php_js.ini = this.php_js.ini || {};    // END REDUNDANT
 
    if (typeof mixed_var === 'object') {
 
        if (this.php_js.ini['phpjs.objectsAsArrays'] &&  // Strict checking for being a JavaScript array (only check this way if call ini_set('phpjs.objectsAsArrays', 0) to disallow objects as arrays)            (
            (this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase &&
                    this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase() === 'off') ||
                parseInt(this.php_js.ini['phpjs.objectsAsArrays'].local_value, 10) === 0)
            ) {            return mixed_var.hasOwnProperty('length') && // Not non-enumerable because of being on parent class
                            !mixed_var.propertyIsEnumerable('length') && // Since is own property, if not enumerable, it must be a built-in function
                                getFuncName(mixed_var.constructor) !== 'String'; // exclude String()
        }
         if (mixed_var.hasOwnProperty) {
            for (key in mixed_var) {
                // Checks whether the object has the specified property
                // if not, we figure it's not an object in the sense of a php-associative-array.
                if (false === mixed_var.hasOwnProperty(key)) {                    return false;
                }
            }
        }
         // Read discussion at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/
        return true;
    }
 
    return false;}
external links: original PHP docs | raw js source

Examples

» Example 1

Running

1
is_array(['Kevin', 'van', 'Zonneveld']);

Should return

1
true

» Example 2

Running

1
is_array('Kevin van Zonneveld');

Should return

1
false

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 is_array 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
Brett Zamir
May 11th Permalink

q  @Mathias Bynens: php.js, in order to support use of object literals as associative arrays (to the extent possible), considers these as "arrays" (while attempting to exclude objects which have inherited properties and thus less likely to have been intended as an associative array). We also allow configuration for people who do not want to treat objects as arrays.

Gravatar
Mathias Bynens
May 10th Permalink

q  Wow, WTF!

What’s wrong with:

function isArray(obj) {
 return '[object Array]' === Object.prototype.toString.call(obj);
};

Gravatar
Brett Zamir
12 May '09 Permalink

q  Sorry, I neglected to add the "phpjs." prefix in a few cases. Fixed now in SVN.

Gravatar
Kevin van Zonneveld
11 May '09 Permalink

q  Great work Brett, I Gotta say!

Gravatar
Brett Zamir
10 May '09 Permalink

q  FYI, I've just added the ability (function in SVN) for you to set the ini (e.g., ini_set('phpjs.objectsAsArrays', 0);) to establish strict type checking for arrays (not any kind of object). However, the default behavior still treats objects as arrays (unless they are objects which inherit properties).

Gravatar
Brett Zamir
30 Apr '09 Permalink

q  Looks like we need one more check:

&& a.constructor !== String

since the rare

var str = new String();

form would otherwise qualify.

Actually if the same frame problem with Array occurs (presumably due to Array constructor being of a different identity), I've wondered why:

!a.constructor || a.constructor.name !== 'Array'

or in our case here:

!a.constructor || a.constructor.name !== 'String'

couldn't do the trick regardless of frames...

If this wouldn't work, we could use the same trick to check for methods that are only built-in on String (as opposed to Array).

Brett

Gravatar
Brett Zamir
30 Apr '09 Permalink

q  You know, unless I'm just getting dizzy from this topic, I think I may have found (or refound?) a foolproof way to establish that something is an array, and only an array (i.e., for strict checking mode).

typeof a === 'object' && a.hasOwnProperty('length') && !a.propertyIsEnumerable('length')

The first test excludes strings, the 2nd test excludes objects with a length property added further up the prototype chain, while the 3rd test excludes objects with a length property added directly on an instance, all while catching arrays. Am I missing something? I don't think there are any other built-in types with a length property...

Brett

Gravatar
Brett Zamir
30 Apr '09 Permalink

q  @KELAN, in the same line as Kevin's question, see also the discussion I had earlier with Luke here. I think my own proposed check for both splice and concat, etc. should be pretty safe, though feedback is welcome.

@Mk. Keck, sorry for the late reply. Rather than overload the arguments to the functions (to which PHP itself might add additional arguments in the future which could conflict with any we add), the approach we are taking for customizability is the same as for PHP: use ini, and to distinguish our own specific ini-setting needs, we can use "phpjs." as a prefix (as though phpjs were an extension to PHP).

So, we can modify things to work like this:

ini_set('phpjs.objectsAsArrays', false);

is_array({prop:'val'}); // false

(If you were curious about the technical details, this can work since is_array() will check for the global this.php_js.ini['phpjs.objectsAsArrays'].local_value set by ini_set() and act accordingly, or default to true if none had been set; 'this' will refer to the global window unless the namespaced version is used, in which case this.php_js will be an instance variable, rather than a global. ("php_js" is reserved as the single global we require in some functions in the non-namespaced version.)

How does that sound?

Gravatar
Kevin van Zonneveld
29 Apr '09 Permalink

q  @ KELAN: Thanks for contributing. I would like to make the same point as here:
http://phpjs.org/functions/view/422#comment_33054 though

Gravatar
KELAN
28 Apr '09 Permalink

q  

function is_array(mixed_var){
	if (mixed_var) return Object.prototype.toString.apply(mixed_var)==='[object Array]';
	else return false;
}

Gravatar
mk.keck
6 Mar '09 Permalink

q  Improved function is_array():
Why not let the user change dynamicly the behavior of is_array()?

[CODE="Javascript"]
function is_array() {
var a = arguments;
if (a.length < 1) {
return false;
}
// Check Value
var v = a[0];
// Check Strict
var s = ( (typeof(a[1]) !== 'undefined' && a[1]) ? 1 : 0 );
if (typeof(v) === 'object') {
if (v.hasOwnProperty) {
for (var k in v) {
// Checks whether the object has the specified
// property if not, we figure it's not an object
// in the sense of a php-associative-array.
if (false === v.hasOwnProperty(k)) {
return false;
}
}
}
// If (s > 0) then strict JavsScript-proof type checking
// is enabled. This will not support PHP associative
// arrays (JavaScript objects), however.
// Read discussion at:
// http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/
if (s > 0) {
if (v.propertyIsEnumerable('length') || typeof(v.length) !== 'number') {
return false;
}
}
return true;
}
return false;
}
[/CODE]

Gravatar
Brett Zamir
10 Feb '09 Permalink

q  Here's my stab at isArray() (I'm not using the PHP format since this doesn't return true for objects/associative arrays) in case any were interested.

function isArray (arr) {
if (arr instanceof Array || // catch most common occurrence and exist quickly if so
(
'splice' in arr.constructor.prototype &&
'concat' in arr.constructor.prototype && // not a word, so may be safer than splice, but can't replace it since concat present on string object
!(arr.propertyIsEnumerable('length')) &&
typeof arr.length === 'number'
)
) {
return true;
}
return false;
}

Gravatar
Brett Zamir
27 Jan '09 Permalink

q  Hi Luke,

Yes, thanks for pointing it out. But also note "Martin B." makes the same observation I did per the "Miller device" on the blog you cite. There's apparently really no foolproof/secure way to conclusively determine something is an array (and only an array) in JS.

Gravatar
Luke
26 Jan '09 Permalink

q  @Brett, FYI, Doug uses the Object.proto.toString method now.

http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=916

Gravatar
Kevin van Zonneveld
25 Jan '09 Permalink

q  @ Luke: Thanks for the heads-up. Interesting article. But for the record: it's not exactly our philosophy to obfuscate object types. I don't even think there is a WE in this matter.

But my view is: that if you're 'inside' php.js, you have a PHP mindset and expect associative arrays to be, well, just arrays.

You'd probably want this to just execute:
[CODE="Javascript"]
var keys = array('0', '1', '2');
var vals = array('a', 'b', 'c');

combined = array_combine(keys, vals);
if (is_array(combined)) { // WILL FAIL IF WE DENY OBJECTS!
print_r(combined);
}
[/CODE]

.. but it clearly doesn't if we don't allow objects to be arrays as well.. And so we've been struggling with imperfection since.

Luckily, if you need the JavaScript-point-of-view of a variable, you can also just use JavaScript code to establish that. If you want the php point-of-view, use php.js functions.

Gravatar
Brett Zamir
25 Jan '09 Permalink

q  Hi Luke,
Clever idea--I like it. Of course it's not foolproof if somebody overrides the Object prototype's toString() (e.g., to list all of its properties). I think an even more robust solution (and one unlikely to fail in an environment which played with built-in prototypes) might simply be to build on Crockford's approach and test for further methods (e.g., 'concat' is a pretty unlikely property) and/or to insist the method is on the prototype (excluding a user from having the property as a direct property). For example, the test, ('concat' in obj.constructor.prototype ), would catch arrays but not even {concat:'something'}. Someone could still do "delete Array.prototype.splice" but I think that would be much less likely than overriding Object.prototype.toString() which has some potential uses.

Gravatar
Luke
24 Jan '09 Permalink

q  While I entirely disagree with the philosophy of obfuscating a purposeful distinction in object types vis Array vs Object in the language you are entreating your consumers to write in, it has recently become best practice in js to check for Array type using this technique:

[CODE="Javascript"]
function isArray(a) {
return Object.prototype.toString.call(a) === '[object Array]';
}
[/CODE]

See this article for reference:
http://thinkweb2.com/projects/prototype/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

Gravatar
Onno Marsman
20 Jan '09 Permalink

q  Hadn't looked at this 'thread' for a while and I see there's still a question from Brett more or less open for me, about the hasOwnProperty solution and the answer to that is pretty much the same as my feelings for the whole framework/configuration idea:

I only use phpjs for the functions that are missing from javascript, and I also use it to promote javascript for other php-developers in my team because they can easily see in this library how some things can be done in javascript. About everything beyond that: I really don't care what happens: as long as I have simple functions that I can copy/paste and there aren't a lot of dependencies (which includes configuration for these functions I guess). The functions I'm talking about don't include is_array or exit or stuff like that, but I guess I've been clear on that.

Gravatar
Kevin van Zonneveld
15 Jan '09 Permalink

q  @ Brett Zamir: It would be cool to see other implementations coming to live. As long as I can focus on a simple robust base, people will have something consistent to build their spinoffs on.

So like I said: Personally I would like to focus on the main php.js library. Still a lot of work to be done there.

But I encourage anyone who takes that and puts it to other use. Even you :)

Gravatar
Brett Zamir
14 Jan '09 Permalink

q  Hi Kevin and Onno,

My feeling is that it's a toss-up. It doesn't bother me though because I really feel that after implementing more of the functions, it will be good to make a customizable version (on my own if you're not interested), since different people may want to handle things differently.

It's not like people can't study a little bit to set up something as potentially useful as this (and they should know what the code is doing before relying on it). A few main global configuration options (though ideally over-rideable on a function-by-function or function-group basis) like

1) When if at all to treat objects as associative arrays

2) Whether to follow PHP strictly or enable some useful customizations (not too many, but a few
that are just too natural/useful to pass up); basically the things in the functions which told people that they could uncomment the given lines (or the ones we wanted to add but felt would deviate too much from PHP--e.g., a file_get_contents() that could be configured to work with asynchronous Ajax, with Firefox (or possibly Explorer) local file access code, etc.)

Gravatar
Kevin van Zonneveld
14 Jan '09 Permalink

q  @ Onno Marsman & Brett Zamir:

What if we traverse the variable and verify that hasOwnProperty returns true for every element, and only then return true for is_array?

That way you can be pretty sure that this object is just a storage container, and nothing fancy otherwise.

Gravatar
Kevin van Zonneveld
31 Dec '08 Permalink

q  @ Onno Marsman: You are totally right. How about the current comment.

@ Brett Zamir: I didn't even know that, I'm amazed actually. Google's got some work to do on improving her engine :)

About the frameworks: Besides the obvious naming conflicts, the main reason I created the namespaced version was for others to be able to more easily extend & build on top of it.

Gravatar
Onno Marsman
30 Dec '08 Permalink

q  Ok, than we'll just leave it to return true on objects.


I do have a tiny little problem (I just can't help myself, sorry) with the comments: "Uncomment to disable support" It's not that it's not supported if you do that, it just behaves differently with all the pros en cons we discussed. If you do feel that it would be disabling support for ..., it wouldn't make any sense to put it there: who would want to disable support for something?

Gravatar
Brett Zamir
30 Dec '08 Permalink

q  Well, it's sure a good sign that people are interested in your project, if it's the third item on Google showing up for "PHP is_array" (after the PHP site and a mirror). Congratulations, wow! And that's without "JavaScript" even in the query (its the first with that one).

I think that's entirely reasonable to avoid the configuration, though I think it could be interesting to integrate it into a separate framework. Heck, maybe I might try something with it later on because I do think it could be very useful.

Gravatar
Kevin van Zonneveld
30 Dec '08 Permalink

q  @ Onno marsman, T. Wild, Brett Zamir: Thanks your insightful comments. Appreciated.

-- PHP.JS: Brett you have laid out what the project is about, and a couple of your paragraphs should probably make it to the phpjs.org site. Thanks. But in this particular case, you're preaching to the choir ;) We have all invested our precious free time in this project, because we are already convinced of it's purpose (and as it turns out, even more people see even more purposes for it, I have even heard people are trying to bring our PHP power to Adobe AIR ;)

-- Configurable PHP.JS:
My vision on the project: I think we should Not try to create a Framework. Let us stick with creating a Library. Others are invited to take our (namespaced / compiled) Library and extend it in whatever way they see fit, we should focus on delivering raw PHP power, as close to the original PHP as reasonably possible. This goal should not provide the need for configuration.

If it's even possible to have a setup file for a library (and still call it that), it would over-complicate & potentially make things unstable. I side with Onno on that one. Besides: there's lower hanging fruit still to be plucked.

-- InstanceOf:
T.Wild thanks for your url http://javascript.crockford.com/remedial.html . In these ways, working on PHP.JS has helped me to get a better understanding of both languages. That's very cool. I've changed the gettype function to fix the type problems stated in your find. I also implemented (& commented) it in the is_array function.

-- is_array:
We once made the decision that PHP.JS should accept associative arrays. I still think we can not make an exception now. Having said we should mimic PHP as much as reasonably possible, I would very much like this code:
[CODE="Javascript"]
var combined;
var keys = ['0', '1', '2'];
var vals = ['a', 'b', 'c'];

combined = array_combine(keys, vals);
if (is_array(combined)) {
print_r(combined);
}
[/CODE]
to produce:
[CODE="Text"]
Array
(
[0] => a
[1] => b
[2] => c
)
[/CODE]
And not ''. I realize that it's choosing between two evils. Maybe it's because I'd rather look at it from an enabling point-of-view, but in my opinion, having it return true on objects (!= 'classes') still is the lesser evil.

-- Paragraphing: There was a bug in my blog that stopped newlines whenever a CODE block was used. Fixed.

Gravatar
Onno Marsman
29 Dec '08 Permalink

q  Ah thanks, now at last I can make my posts readable. Let's see if this works...


About configuration: there's the danger of a lot of discussions being settled with "let's make it configurable" and that will make a lot of things unclear. Without wanting to start a discussion about that topic, in my opinion, this is exactly where most open source PHP CMS products known to me take a wrong turn. You get a lot of imaginary spin offs only by personal preference configuration which have to be maintained, and this causes a lot of bugs: a programmer tends to find and solve a bug only with his preferable configuration.


Especially with a project like this which is generally very simple, I think we should put a lot of effort in keeping it simple. If we have to make decisions we can't all agree with: too bad. Even if I would be the only one to think something should be solved differently and therefor it wouldn't be done that way, I probably wouldn't agree on making it configurable. This would be the case in the discussion about is_array right here: it's just not important enough.

I'm not saying configuration shouldn't be there at all. There might be some cases where configuration can be a good thing, although I can't think of one right now. Anyway, I think, we shouldn't use it for settling a discussion, and only use it when there is really no alternative.


About configuration by function parameters: like you said, this is a really bad idea and shouldn't be considered an option indeed.


Of course, about all these issues, I can only speak for myself.... I wonder what Kevin has to say about all of these things. He has a lot of reading to do ;)

Gravatar
Brett Zamir
29 Dec '08 Permalink

q  Onno: I thought so, but you could have been just doing it as a learning exercise. But, honestly, I wasn't targeting it at you really, I just felt I had to get that off my chest. :) Sorry about that.


I don't think that configuration is making things complicated unless the default behavior is unreasonable. Although it's usually nicer to do it by passing in an argument (if you like the PHP-style that is), since we don't really have that option, I think offering a choice is convenient and allows the library to be shared more widely. Imagine, for example, just keeping your PHP functions followed by configuration setup (if you felt the need to customize) all in one file. You could just reuse that without needing to worry about it.


What do you think about the idea of adding a module property and constants?


For paragraphing, as I only discovered this last post, was to make two lines between each.

Gravatar
Onno Marsman
28 Dec '08 Permalink

q  Brett: I'm of course talking about this function (and some other) and not the complete library, why else would I bother to participate in any way? You're defending the need of the whole library to me: you really don't need to, I share your opinion about that obviously.
--------
The in_array function seems useful to me too when you consider the whole frame/window issue, but that's a problem I don't think I will encounter very often. And when it would return true on objects (as it does now) that whole problem wouldn't even exist, and the function would seem useless to me anyway. And that's why I'm saying I probably would never use this function. My point on configuration making things complicated remains.
------
One more question to you, Brett: could you please tell me how to post in paragraphs on this site? My posts continue to result in large ugly blobs of text.

Gravatar
Brett Zamir
28 Dec '08 Permalink

q  Hi Onno: Well, for this function alone it would no doubt be overkill (the OOP way), but I don't think that PHP-JS is merely useful in helping students of PHP transition to JS, though that is a good benefit.


What is useful, I think, is that PHP has defined a vocabulary for a wide range of standard processing people want to do on Strings, Arrays, etc., functions which are completely lacking in JavaScript--a language that was standardized early on, and had little time to acquire even basic utility facilities, despite it being a flexible language).


PHP provides a kind of expressive vocabulary to be able to do things, and with which many users may already be familiar with the terminology. No doubt a large part of what people like about PHP is its large number of functions.


And for is_array(), I think many experienced programmers would be glad to save themselves the trouble of having to type the same long fail-safe string over and over again that you all were discussing (to avoid the different window/frame problem).


Personally speaking, I'm more drawn to the utility (and elegance) of other functions like array_values() or array_keys(), or even in_array(). I don't want to have to write a for loop every time I need one of them or even when I can use "indexOf() !== -1", in_array() is so much more elegant. Seriously, what's wrong with saving yourself time and making your code more intelligible?


Of course, some will look down on this because either this is not the "JavaScript way" (if it's OOP, saves lines of code, and doesn't have any negative side effects, I don't see how it isn't) or because it pays homage to a language which is just too darn easy to learn and do useful things with.


It's like people who will respect you if you learn ancient Egyptian but think nothing of you learning Spanish. If it's useless and difficult, then it deserves praise. Or when people prefer the status quo of not having an official world auxiliary language because they think it is charming that we can't communicate with each other (or just expect that everyone should spend all of their time mastering various languages, rather than working for a global agreement to have one language (whether English, Esperanto, or whatever could garner the most support) be taught along with native languages in schools around the world). Does humanity really need scores of words for "apple" when we could settle on one language in addition to our native one? (thousands of words, I know, but I'm only talking about reducing lingua francas, not native languages) Does inter-communication need to be only for those with privilege and too much free time?


Why does a JavaScript library (that has no JavaScript standard to work from) need to start from scratch as far as terminology as well as functionality? Isn't it helpful to be able to piggy-back on something already existing?


Sorry for this diatribe (I'm not at all responding to your honest question), but this just raised the topic for me of all the maligning people do
in other discussions I've had because human beings like to lord over the "right way", and conversely, proponents of practicality are often too cowed to defend the useful albeit ordinary, while others are afraid to think for themselves and resist the impulse to second-guess oneself when everyone else is criticizing something you find useful. Criticism itself is usually such a waste of time, where we should be honestly discussing in a humble manner (like your nice polite but frank question) which way is better.


I'm doing JavaScript for full-time paid work (building Firefox extensions), and I've unabashedly been using some of these utilities. I particularly like array_unique(), trim, and Mozilla equivalents I've made for file_get_contents() and file_put_contents().


Oh, and I see I'm using your min() function too! :) Given that you found a need to write a good many lines of code for that function, do you really want to rewrite that each time you need it or give it a non-PHP name? :)

Gravatar
Onno Marsman
28 Dec '08 Permalink

q  Brett: Isn't this making things a bit to complicated for something that's just meant to help a PHP programmer make the step to JS? I mean: no experienced JS programmer is ever gonna use this function anyway and I don't think a not so experienced one would wanna find out how to configure something like this. I think it would even be easier and clearer to fall back to "instanceof Array" or "instanceof Object", whichever one they need.
PHP doesn't have this kind of configuration either and if we would introduce it I doubt anybody would use it.

Gravatar
Brett Zamir
28 Dec '08 Permalink

q  Sorry, my OOP code had a bug...Here's a fix:

[CODE="Javascript"]function PHP_JS (config) {
this.JS = {};
for (var php_js_method in this) { // Add JS config property for all PHP-JS functions
if (typeof this[php_js_method] === 'function') {
this.JS[php_js_method] = {};
}
}
for (var method in config) {
var configObj = config[method];
this.JS[method] = configObj;
}
}
PHP_JS.prototype = {
is_array : function (mixed_var) {
if (this.JS.is_array.objectsAsArrays) {
return (mixed_var instanceof Object);
}
return mixed_var && !(mixed_var.propertyIsEnumerable('length')) && typeof mixed_var === 'object' && typeof mixed_var.length === 'number';
}
}

var PHP1 = new PHP_JS({is_array:{objectsAsArrays:true}});
var PHP2 = new PHP_JS({is_array:{objectsAsArrays:false}});
alert( PHP1.is_array({}) ); // true
alert( PHP2.is_array({}) ); // false
PHP1.JS.is_array.objectsAsArrays = false; // Can still reconfigure if needed too
PHP2.JS.is_array.objectsAsArrays = true;
alert( PHP1.is_array({}) ); // false
alert( PHP2.is_array({}) ); // true
[/CODE]

Gravatar
Brett Zamir
28 Dec '08 Permalink

q  In order for PHP-JS to work as a bona-fide framework (which I think it could well become), there is a need for configurability, as seen in this discussion. And while a decision must still be made as to default behavior, I think that we can take advantages features of JavaScript which PHP does not have, in order to allow that configurability without adding additional arguments to the functions (which might have additional ones assigned by PHP in the future): adding properties to the functions themselves. (My apologies if others have suggested this.)

My suggestion is to reserve "JS" as an object for configurability. For example, one might do:

[CODE="Javascript"]function is_array (mixed_var) {
if (arguments.callee.JS.objectsAsArrays) {
return (mixed_var instanceof Object);
}
return mixed_var && !(mixed_var.propertyIsEnumerable('length')) && typeof mixed_var === 'object' && typeof mixed_var.length === 'number';
}
is_array.JS = {};

is_array.JS.objectsAsArrays = true;
alert( is_array({}) ); // true
is_array.JS.objectsAsArrays = false;
alert( is_array({}) ); // false[/CODE]

The internal code would simply check for "if ({func_name}.JS.{prop_name})", (adding the empty JS object right after the function declaration) and act accordingly. I believe this could really be useful, especially for functions with no easy parallel in native JavaScript, but where the nature of JavaScript suggests different possible behaviors for the functions (or for adding other ideas PHP didn't think of).

We might even handle this in an OOP way (to more easily allow different configurations for the functions in different contexts), if the "namespace" for our PHP-JS objects were to be given by a constructor function. For example,

[CODE="Javascript"]
var PHP1 = new PHP_JS({is_array:{objectsAsArrays:true}});
var PHP2 = new PHP_JS({is_array:{objectsAsArrays:false}});
alert( PHP1.is_array({}) ); // true
alert( PHP2.is_array({}) ); // false
PHP2.JS.is_array.objectsAsArrays = true; // Can still reconfigure if needed too
alert( PHP2.is_array({}) ); // true

function PHP_JS (config) {
this.JS = {};
for (var php_js_method in this) { // Add JS config property for all PHP-JS functions
if (typeof this[php_js_method] === 'function') {
this.JS[php_js_method] = {};
}
}
for (var method in config) {
var configObj = config[method];
this.JS[method] = configObj;
}
}
PHP_JS.prototype = {
is_array : function (mixed_var) {
if (arguments.callee.JS.objectsAsArrays) {
return (mixed_var instanceof Object);
}
return mixed_var && !(mixed_var.propertyIsEnumerable('length')) && typeof mixed_var === 'object' && typeof mixed_var.length === 'number';
}
}[/CODE]

Whether using the OOP approach or not, your configuration questions (objectsAsArrays, functionsDisallowed, etc.) could be handled.

For either of these approaches (of adding properties to the functions or namespace object), PHP constants could be added relating to that function (thus not requiring defining every possible PHP constant or polluting the global namespace further), or meta-data could be attached relating to that function vis-a-vis PHP such as to indicate to which module it belongs (or put the constants within the module information). Thus, a property could be used to indicate to which PHP module a given function belonged (if one was not already using namespaces to do so). Then one could do things like: extension_loaded(), get_loaded_extensions(), get_extension_funcs(), and get_defined_constants(true) as these functions could reflect upon the meta-data stored for each function.

Although the following is not strictly PHP behavior since Array functions are not an extension in PHP (though we can override this with configuration as described above), we could do things like:

[CODE="Javascript"]if (!extension_loaded('array')) {
function is_array () {
....
}
function in_array () {
....
}
....etc.
}[/CODE]

Gravatar
Onno Marsman
27 Dec '08 Permalink

q  Wow, that's really weird! I guess your find is a better implementation than "instanceof Array" then. I'm curious about what Kevin thinks about all of this now.

Gravatar
T.Wild
27 Dec '08 Permalink

q  To be honest, Onno, put like that I would have to agree. Better to have it return false and know why then work around it, than have something you think works but be unable to explain why it goes wrong. I still feel that closer PHP behavior should be the goal, and returning true on associative arrays [objects] does this, but I guess you are unlikely to ever get this because of the basic fact that arrays are objects. So what's my decision? I'd have to say the former, but I'm left sitting on the fence somewhat. :)
------------------------------------
Now, if this function does get converted to returning true on TRUE arrays only, when I've been looking around the internet I found this version of is array:
http://www.hunlock.com/blogs/Mastering_Javascript_Arrays#quickIDX34
[CODE="javascript"]
function isArray(testObject) {
return testObject && !(testObject.propertyIsEnumerable('length')) && typeof testObject === 'object' && typeof testObject.length === 'number';
}
[/CODE]
I did wonder why something like this was needed but i found an explanation on this site:
http://javascript.crockford.com/remedial.html

[value instanceof Array] will only recognize arrays that are created in the same context (or window or frame). JavaScript does not provide an infallible mechanism for distinguishing arrays from objects, so if we want to recognize arrays that are constructed in a different frame, then we need to do something more complicated.

P.S. I haven't found any real use for this outside PHP either.

Gravatar
Onno Marsman
27 Dec '08 Permalink

q  @T.Wild: Returning true on objects doesn't mimic PHP any better than returning false would. You're looking at it from a "when should it return true" point of view. You could also look at it from a "when should it return false" point of view. From the "return false" point of view I can't really explain the current "return true on object and array" implementation, while "return true only on arrays" can be explained, I think, from both point of views.
[CODE="Javascript"]

[/CODE]
About finding a reliable method: I'm pretty sure there isn't one.
[CODE="Javascript"]

[/CODE]
Ah well, I would never use this function anyway and would do it the JS way, so I won't make any more fuss about this. I just would hate to see some functions of this library slip off into a state of "behaves a little but more like PHP on some fronts but is really confusing so nobody would ever dare to use it"

Gravatar
T.Wild
24 Dec '08 Permalink

q  I guess I'm just going to add fuel to the fire on this but IMO what JavaScript sees as an array/object isn't the issue but what PHP would since that's what we're trying to imitate is it not?
*
I agree in this sort of situation you just don't know what an object is intended as, but i think it's still better to return true for both arrays AND objects at least until a reliable method can be found to tell the difference between an object and an 'associative array', if one exists.

Gravatar
Onno marsman
17 Dec '08 Permalink

q  How should I post in paragraphs?[br]
[br]
test. If this worked... never mind ;)

Gravatar
Onno Marsman
17 Dec '08 Permalink

q  I guess you're missing my point.
I'm saying PHP's is_array checks the type of the variable, I think so should php.js' is_array.<br><br>

I mean: think of when you would you use this function. I think it would only make sense if you'd wanna check the type of a variable.<br><br>

For functions that expect arrays it's simple: we just treat objects as arrays. Here we just don't know what to expect and there really is no way of knowing whether an object is intended as an array or not.<br><br>

Remember the post from someone that wanted to create an array syntax like this:
[CODE="Javascript"]
array(" 'first' => 'kevin' ", " 'last' => 'Zonnevelt' " );
[/CODE]
You agreed with me it would weird to create a new syntax that is not really the same as php, while js already has a syntax that is not really the same as php.<br>
I guess you could say the same about this issue: why create a new definition of what an array is that is not really the same as in php, while js already has a definition of what an array is that is not really the same as in php.

Gravatar
Kevin van Zonneveld
17 Dec '08 Permalink

q  @ Onno Marsman: Yes, "associative array in JS is an object so it's not an array". But we're trying to implement PHP's is_array, and not JavaScript's definition of it.

Saying that PHP.JS should support associative arrays (objects), and making an exception for the most profound function in this category: is_array, is not making any sense.

What does make sense to me, is your argument that an array of functions is also an array. Thus scanning for functions to make a slight distinction between 'class-like-objects' and 'array-like-objects', can not be achieved that way.

Insert insightfull comment here ;)

Gravatar
Onno Marsman
10 Dec '08 Permalink

q  And of course the current implementation is still the same as the following:
[CODE="Javascript"]
function is_array( mixed_var ) {
return (mixed_var instanceof Object);
}
[/CODE]

Gravatar
Onno Marsman
10 Dec '08 Permalink

q  You know I agree with you that php.js should support associative arrays. But I stay with my argument that is_array should return whether a variable is an array. An associative array in JS is an object so it's not an array.

About your example: I would argue what you are suggesting: check for false.

About scanning for functions: that results in some weird situations. We'd also have to change the implementation of is_object and it could theoretically result in situations where is_array returns true on a variable which after a few manipulations returns false. Furthermore: what to do with something like this:
[CODE="Javascript"]
var a = [function() { }];
[/CODE]
Is this an object or an array, or both?
Or what if I would really just want to store some functions in an associative array? It is possible.
What I'm saying that the boundary just wouldn't be clear and that would just result in people not trusting these functions.

We should keep it simple: is_array is about type checking and returns true when it is an array. It's a very clear boundary, it is much easier to explain, defend and implement. Of course that doesn't mean we shouldn't support associative arrays.

Gravatar
Kevin van Zonneveld
10 Dec '08 Permalink

q  @ Onno Marsman: Thanks for your input, the thought crossed my mind as well. Well, this is going to be dirty, so please buckle up Onno.. Please bear the following code:

[CODE="Javascript"]
var myResult, input = {'firstname': 'Onno', 'surname': 'Marsman'};
myResult = filterData(input); // Will only return array (object) on success
if (!is_array(myResult)) {
alert('Data could not be filtered!');
} else {
for (key in myResult) {
// process data
}
}
[/CODE]

You can bet that people are going to use is_array in such ways.

Though you may argue that people 'd better use:
[CODE="Javascript"]
if (false === myResult) {
[/CODE]
.. to check if filterData() worked correctly - and I would have agree with you, that doesn't mean that I want the first code to fail in php.js, just because we say that's not good coding habit. php.js isn't foolproof but we should try to make it whenever we face decisions like this.

Although it may even mean we have to scan for functions within objects to distinct them from associative arrays, I still think we have to stick with our idea of supporting associative arrays, and not make exceptions in this function.

I really do agree that is_object & is_array should differ though. So I will work on the function scanning. If you have any ideas on that (or still don't agree with me) please let me know.

Gravatar
Onno Marsman
4 Dec '08 Permalink

q  Isn't this the same as
[CODE="Javascript"]
return (mixed_var instanceof Object);
[/CODE]
or
[CODE="Javascript"]
return (typeof mixed_var=='object');
[/CODE]
?

Also: If mixed_var is an object which has functions then I don't think this function should return true. We could check for that, but in turn it makes you wonder what to do with the implementation of is_object. Does an object needs to have a function? I don't think so. This would mean that is_object(v) and is_array(v) can both be true at the same time, that doesn't make any sense when you think PHP.

In my opinion we're taking this to far. I think is_array is clearly meant to only check the type of the variable. I don't think we'll miss out an anything if it doesn't return true on associative arrays. In JS they just aren't arrays but objects so therefor imho for associative arrays is_array should return false and is_object should return true.

Gravatar
Kevin van Zonneveld
1 Dec '08 Permalink

q  @ Manish: In php.js, javascript objects are indeed like php associative arrays

Gravatar
Manish
25 Nov '08 Permalink

q  function is_array(input)
{
if( typeof input == 'object' && input instanceof Array )
{
return true;
}

return false;
}

Gravatar
Kevin van Zonneveld
18 Jul '08 Permalink

q  I'm nowhere near as good as I would like to be. But I'm trying. Glad you find these pages useful though.

Gravatar
Marce
7 Jul '08 Permalink

q  Tranks kevin, this function is good :), you are very good programer.

Gravatar
Mat
19 Jun '08 Permalink

q  Great!

Gravatar
Kevin van Zonneveld
4 Jan '08 Permalink

q  @ Andrey: Thank you I've updated the function!

Gravatar
Andrey
4 Jan '08 Permalink

q  I found a more simple sample:

function is_array(a) {
return (a instanceof Array);
}


Contribute a New function

More functions

In this category

doubleval
empty
floatval
get_defined_vars
get_resource_type
gettype
import_request_variables
intval
» is_array
is_binary
is_bool
is_buffer
is_callable
is_double
is_float
is_int
is_integer
is_long
is_null
is_numeric
is_object
is_real
is_resource
is_scalar
is_string
is_unicode
isset
print_r
serialize
settype
strval
unserialize
var_dump
var_export

Support us

spread the word:


Use any PHP function in JavaScript


These kind folks have already donated: @HalfWinter, Paulo Freitas, Andros Peña Romo, Nitin Gupta, @nikosdion, Anonymous, Anonymous and Shawn Houser.
<your name here>

Click here to lend your support to: phpjs and make a donation at www.pledgie.com !