phpjs
Version:
1,063 lines (799 loc) • 51.2 kB
HTML
<!-- Generated by Rakefile:build -->
<strong>
<a href="lcfvs.monespace.net/perso" rel="nofollow">Lcf.vs</a>
</strong>
on 2011-07-02 12:34:09 <br />
Me>
<pre><code>
var test;
test=[]; // true
test=[[]]; // true
test=[new Array()]; // true
test=new Array(); // true
test=new Array([]); // true
test=new Array(new Array()); // true
test[1]=3; // true
test={}; //false
test[0]=1; //false
</code></pre>
What else?
<hr />
<strong>
Me
</strong>
on 2011-07-02 11:29:50 <br />
@Lcf.vs: You can find an answer to your question here http://phpjs.org/functions/is_array:437#comment_112008
<hr />
<strong>
<a href="lcfvs.monespace.net/perso" rel="nofollow">Lcf.vs</a>
</strong>
on 2011-07-02 00:39:50 <br />
Why complicate?
<pre><code>
function isArray(supposedArray){
return supposedArray instanceof Array;
}
</code></pre>
<hr />
<strong>
Nathan Sepulveda
</strong>
on 2011-03-16 19:28:09 <br />
@Brett: Thanks!
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2011-03-15 04:09:11 <br />
@Nathan (Sepulveda): Fixed in Git. Thanks!
<hr />
<strong>
Nathan Sepulveda
</strong>
on 2011-03-14 23:16:22 <br />
I was wondering if you could put my last name on the credits for this function, I only say this because the name "Nathan" links to two different contributions, but I have only contributed on this function, and not to the htmlspecialchars function and I would like to make that distinction. Thanks.
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2011-01-02 10:49:15 <br />
@abdelrahman salem: That's a good one, unless you pass in a string constructed by a String constructor:
<pre><code>is_array(new String('abc')); // true</code></pre>
(or if you override propertyIsEnumerable)
There seem to be no 100% perfect solutions for this one...
<hr />
<strong>
<a href="http://jo.linkedin.com/in/abdsalem" rel="nofollow">abdelrahman salem</a>
</strong>
on 2011-01-02 09:27:05 <br />
<pre><code>
function is_array(inputArray) {
return inputArray && !(inputArray.propertyIsEnumerable('length')) && typeof inputArray === 'object' && typeof inputArray.length === 'number';
}
</code></pre>
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2010-11-30 16:09:54 <br />
@Nathan: I adapted your code a bit and added to Git, thanks for the patches. We still want to keep the INI settings so that people can force this function to disallow objects from being considered as arrays. I also kept part of the old way in the comments because the old way was also valid and even harder to get a false result, but I agree your solution is simpler.
<hr />
<strong>
Nathan
</strong>
on 2010-11-24 19:35:51 <br />
Sorry for the reposts, feel free to remove the other one below, I didn't know the code would be hidden, and I forgot to remove a this:
<pre><code>
function is_array (mixed_var)
{
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;
}
if(Object.prototype.toString.call(mixed_var) === "[object Array]")
{
return true;
}
else if(Object.prototype.toString.call(mixed_var) === "[object Object]" &&
getFuncName(mixed_var.constructor) === "Object")
{
return true;
}
return false;
}
</code></pre>
<hr />
<strong>
Nathan
</strong>
on 2010-11-24 19:30:49 <br />
REVISION:
<pre><code>
function is_array (mixed_var)
{
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;
}
if(Object.prototype.toString.call(mixed_var) === "[object Array]")
{
return true;
}
else if(Object.prototype.toString.call(mixed_var) === "[object Object]" && this.getFuncName(mixed_var.constructor) === "Object")
{
return true;
}
return false;
}
</code></pre>
<hr />
<strong>
Nathan
</strong>
on 2010-11-24 19:26:09 <br />
@Brett: I posted some code earlier and it hasn't shown up, I used the constructor and was able to shorten the above function to only a few lines:
<pre><code>
if(Object.prototype.toString.call(mixed_var) === "[object Array]")
{
return true;
}
else if(Object.prototype.toString.call(mixed_var) === "[object Object]")
{
if(getFuncName(mixed_var.constructor) === "Object")
{
return true;
}
}
return false;
</code></pre>
(of course, I need to add the getFuncName function, but you already have it)
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2010-11-24 12:57:56 <br />
@Nathan: Pretty much, yes (by default). But this should probably be checking the constructor property instead to see whether it is a regular function or the built-in object constructor, since the current approach would allow some non-inheriting objects created with "new" to be considered as associative arrays (though maybe some would like it that way).
Another issue with associative arrays is ECMAScript's annoyingly unpredictable iteration order, so I'm hoping we can allow array() to allows objects to be built something like this, with multiple objects passed as arguments to preserve order: var arr = array({key1:'val1'}, {key2:'val2'});.
Yet another related issue is how IE doesn't really delete properties, as it remembers their iteration sequence, making it impossible for us to sort arrays in place (thus requiring us to deviate from PHP and return a copy of the array). The proposal I mentioned would deal with this problem too, albeit in a regrettably but necessarily ugly way.
<hr />
<strong>
Nathan
</strong>
on 2010-11-22 21:20:20 <br />
@Zamir: I can see how instanceof would have have issues with a user defining their own Array object. As for frames, they just shouldn't be used, but, seeing as they are, and that they are available, one must program for them. As for associative arrays, according the function above, are we assuming that all literal objects (meaning "var myObj = {};") are considered assoc arrays, and that all non-literal objects (such as functions and javascript psuedo-classes (via the prototype) are to be then considered objects? The only exception here of course being the Array class. This makes sense to me, I just have never programmed for assoc arrays in javascript because I really just have never had the time, and now that I do, here I am.
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2010-11-22 07:41:11 <br />
@Nathan: Although I can't see Andrey's comment here, what you cite is not supposed to work across frames because "Array" will be a different constructor on another frame: http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ (also if someone defined their own Array: "var Array = function () {}"). Also, in our case, we may treat objects as arrays, since we allow them potentially as associative arrays.
<hr />
<strong>
Nathan
</strong>
on 2010-11-21 22:27:06 <br />
I agree with Andrey, I cannot find a single instance where:
<pre><code>
function is_array(mixed_var)
{
return mixed_var instanceof Array;
}
</code></pre>
does not work.
<hr />
<strong>
Nathan
</strong>
on 2010-11-21 22:25:05 <br />
I agree with Andrey, I cannot find a single instance where:
<pre><code>
function is_array(mixed_var)
{
}
</code></pre>
<hr />
<strong>
<a href="http://brett-zamir.me" rel="nofollow">Brett Zamir</a>
</strong>
on 2010-05-11 06:35:58 <br />
@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.
<hr />
<strong>
<a href="http://mathiasbynens.be/" rel="nofollow">Mathias Bynens</a>
</strong>
on 2010-05-10 19:01:16 <br />
Wow, WTF!
What’s wrong with:
<pre><code>function isArray(obj) {
return '[object Array]' === Object.prototype.toString.call(obj);
};</code></pre>
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-05-12 02:43:39 <br />
Sorry, I neglected to add the "phpjs." prefix in a few cases. Fixed now in SVN.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2009-05-11 17:38:55 <br />
Great work Brett, I Gotta say!
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-05-10 12:23:20 <br />
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).
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-04-30 05:05:22 <br />
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
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-04-30 04:55:24 <br />
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
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-04-30 04:20:35 <br />
@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?
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2009-04-29 15:27:46 <br />
@ KELAN: Thanks for contributing. I would like to make the same point as here:
http://phpjs.org/functions/view/422#comment_33054 though
<hr />
<strong>
KELAN
</strong>
on 2009-04-28 09:00:02 <br />
<pre><code>
function is_array(mixed_var){
if (mixed_var) return Object.prototype.toString.apply(mixed_var)==='[object Array]';
else return false;
}
</code></pre>
<hr />
<strong>
mk.keck
</strong>
on 2009-03-06 16:21:20 <br />
Improved function is_array():
Why not let the user change dynamicly the behavior of is_array()?
<pre><code>
function is_array() {
var a = arguments;
if (a.length &lt; 1) {
return false;
}
// Check Value
var v = a[0];
// Check Strict
var s = ( (typeof(a[1]) !== 'undefined' &amp;&amp; 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 &gt; 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 &gt; 0) {
if (v.propertyIsEnumerable('length') || typeof(v.length) !== 'number') {
return false;
}
}
return true;
}
return false;
}
</code></pre>
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-02-10 08:17:55 <br />
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 &amp;&amp;
'concat' in arr.constructor.prototype &amp;&amp; // not a word, so may be safer than splice, but can't replace it since concat present on string object
!(arr.propertyIsEnumerable('length')) &amp;&amp;
typeof arr.length === 'number'
)
) {
return true;
}
return false;
}
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-01-27 05:19:55 <br />
Hi Luke,
Yes, thanks for pointing it out. But also note &quot;Martin B.&quot; makes the same observation I did per the &quot;Miller device&quot; 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.
<hr />
<strong>
<a href="http://lucassmith.name" rel="nofollow">Luke</a>
</strong>
on 2009-01-26 04:54:55 <br />
@Brett, FYI, Doug uses the Object.proto.toString method now.
http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=916
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2009-01-25 14:32:46 <br />
@ 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:
<pre><code>
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></pre>
.. 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.
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-01-25 08:51:56 <br />
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 &quot;delete Array.prototype.splice&quot; but I think that would be much less likely than overriding Object.prototype.toString() which has some potential uses.
<hr />
<strong>
<a href="http://lucassmith.name" rel="nofollow">Luke</a>
</strong>
on 2009-01-24 23:10:35 <br />
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:
<pre><code>
function isArray(a) {
return Object.prototype.toString.call(a) === '[object Array]';
}
</code></pre>
See this article for reference:
http://thinkweb2.com/projects/prototype/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
<hr />
<strong>
Onno Marsman
</strong>
on 2009-01-20 18:56:28 <br />
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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2009-01-15 11:15:30 <br />
@ 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 :)
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2009-01-14 16:23:56 <br />
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.)
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2009-01-14 14:59:54 <br />
@ Onno Marsman &amp; 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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2008-12-31 10:56:27 <br />
@ 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.
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-30 20:20:20 <br />
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: &quot;Uncomment to disable support&quot; 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?
<hr />
<strong>
Brett Zamir
</strong>
on 2008-12-30 17:15:00 <br />
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 &quot;PHP is_array&quot; (after the PHP site and a mirror). Congratulations, wow! And that's without &quot;JavaScript&quot; 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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2008-12-30 15:30:29 <br />
@ 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 &amp; 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 (&amp; 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:
<pre><code>
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></pre>
to produce:
<pre><code>
Array
(
[0] =&gt; a
[1] =&gt; b
[2] =&gt; c
)
</code></pre>
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.
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-29 10:39:53 <br />
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 &quot;let's make it configurable&quot; 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 ;)
<hr />
<strong>
Brett Zamir
</strong>
on 2008-12-29 01:29:54 <br />
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.
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-28 22:46:22 <br />
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.
<hr />
<strong>
Brett Zamir
</strong>
on 2008-12-28 14:16:37 <br />
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 &quot;indexOf() !== -1&quot;, 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 &quot;JavaScript way&quot; (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 &quot;apple&quot; 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 &quot;right way&quot;, 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? :)
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-28 11:13:56 <br />
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 &quot;instanceof Array&quot; or &quot;instanceof Object&quot;, 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.
<hr />
<strong>
Brett Zamir
</strong>
on 2008-12-28 02:54:42 <br />
Sorry, my OOP code had a bug...Here's a fix:
<pre><code>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 &amp;&amp; !(mixed_var.propertyIsEnumerable('length')) &amp;&amp; typeof mixed_var === 'object' &amp;&amp; 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></pre>
<hr />
<strong>
<a href="http://bahai-library.com" rel="nofollow">Brett Zamir</a>
</strong>
on 2008-12-28 02:42:38 <br />
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 &quot;JS&quot; as an object for configurability. For example, one might do:
<pre><code>function is_array (mixed_var) {
if (arguments.callee.JS.objectsAsArrays) {
return (mixed_var instanceof Object);
}
return mixed_var &amp;&amp; !(mixed_var.propertyIsEnumerable('length')) &amp;&amp; typeof mixed_var === 'object' &amp;&amp; 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></pre>
The internal code would simply check for &quot;if ({func_name}.JS.{prop_name})&quot;, (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 &quot;namespace&quot; for our PHP-JS objects were to be given by a constructor function. For example,
<pre><code>
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 &amp;&amp; !(mixed_var.propertyIsEnumerable('length')) &amp;&amp; typeof mixed_var === 'object' &amp;&amp; typeof mixed_var.length === 'number';
}
}</code></pre>
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:
<pre><code>if (!extension_loaded('array')) {
function is_array () {
....
}
function in_array () {
....
}
....etc.
}</code></pre>
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-27 23:07:02 <br />
Wow, that's really weird! I guess your find is a better implementation than &quot;instanceof Array&quot; then. I'm curious about what Kevin thinks about all of this now.
<hr />
<strong>
T.Wild
</strong>
on 2008-12-27 18:21:00 <br />
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
<pre><code>
function isArray(testObject) {
return testObject &amp;&amp; !(testObject.propertyIsEnumerable('length')) &amp;&amp; typeof testObject === 'object' &amp;&amp; typeof testObject.length === 'number';
}
</code></pre>
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.
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-27 11:34:14 <br />
@T.Wild: Returning true on objects doesn't mimic PHP any better than returning false would. You're looking at it from a &quot;when should it return true&quot; point of view. You could also look at it from a &quot;when should it return false&quot; point of view. From the &quot;return false&quot; point of view I can't really explain the current &quot;return true on object and array&quot; implementation, while &quot;return true only on arrays&quot; can be explained, I think, from both point of views.
<pre><code>
</code></pre>
About finding a reliable method: I'm pretty sure there isn't one.
<pre><code>
</code></pre>
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 &quot;behaves a little but more like PHP on some fronts but is really confusing so nobody would ever dare to use it&quot;
<hr />
<strong>
T.Wild
</strong>
on 2008-12-24 11:42:38 <br />
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.
<hr />
<strong>
Onno marsman
</strong>
on 2008-12-17 22:22:54 <br />
How should I post in paragraphs?[br]
[br]
test. If this worked... never mind ;)
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-17 22:21:21 <br />
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.&lt;br&gt;&lt;br&gt;
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.&lt;br&gt;&lt;br&gt;
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.&lt;br&gt;&lt;br&gt;
Remember the post from someone that wanted to create an array syntax like this:
<pre><code>
array(&quot; 'first' =&gt; 'kevin' &quot;, &quot; 'last' =&gt; 'Zonnevelt' &quot; );
</code></pre>
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.&lt;br&gt;
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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2008-12-17 12:43:45 <br />
@ 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 ;)
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-10 18:52:33 <br />
And of course the current implementation is still the same as the following:
<pre><code>
function is_array( mixed_var ) {
return (mixed_var instanceof Object);
}
</code></pre>
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-10 18:50:25 <br />
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:
<pre><code>
var a = [function() { }];
</code></pre>
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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2008-12-10 17:10:08 <br />
@ 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:
<pre><code>
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></pre>
You can bet that people are going to use is_array in such ways.
Though you may argue that people 'd better use:
<pre><code>
if (false === myResult) {
</code></pre>
.. 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 &amp; 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.
<hr />
<strong>
Onno Marsman
</strong>
on 2008-12-04 21:31:07 <br />
Isn't this the same as
<pre><code>
return (mixed_var instanceof Object);
</code></pre>
or
<pre><code>
return (typeof mixed_var=='object');
</code></pre>
?
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.
<hr />
<strong>
<a href="http://kevin.vanzonneveld.net" rel="nofollow">Kevin van Zonneveld</a>
</strong>
on 2008-12-01 08:34:12 <br />
@ Manish: In php.js, javascript objects are indeed like php associative arrays
<hr />
<strong>
Manish
</strong>
on 2008