PHP is dynamically typed but: null != 'null'



  • Was working on WC(WatchCompany)'s ASS(After Sales Services) and came across this in one of the modules.

    I knew PHP was dynamically typed but this is really taking things too far

    class SomeSingleton {
    	private $_loginInfoId = 'null';
    	private $_languageId = 'null';
    	private $_statusLevel = 'null';
    	
    	protected function updateUserParams () {
    		if(!$this->_loginInfoId || !$this->_languageId || !$this->_statusLevel) {
    			// get user params
    			$authManager = AuthManager::getInstance();
    			$user = $authManager->getUser();
    
    			$this->_loginInfoId = $user->id;
    			$this->_languageId = $user->language;
    			$this->_statusLevel = $user->level;
    		}
    	}
    }
    

    But I think this is because of:

    private function getProcData($proc, $params = null) {
    	$app = Application::getInstance() ;
    	$this->updateUserParams();
    
    if(!$dba = $app->getDb()) {
    	throw new Exception("Cannot retreive db adapter");
    }
    
    try {
    	$qry = 'EXECUTE [dbo].[' . $proc . '] ' . $this->_loginInfoId . ', ' . $this->_languageId . ', ' . $this->_statusLevel . ($params ? ', ' . implode(', ', $params) : '') . ', 0';
    	$stmt = $dba->prepare($qry) ;
    	
    	$output = '';
    	if($stmt->execute(array())) {
    		$res = array(
    			'output' => $output,
    			'records' => $stmt->fetchAll(),
    		) ;
    		return $res['records'];
    	}
    } 
    catch(Exception $e) {
    	throw new Exception("StoredProc $qry: {$e->getMessage()}");
    }
    
    return false;
    

    }



  •  What exactly is yor problem again? 'null' is a string. null isn't. Case closed.



  •  I agree, this is not a wtf at all. A bigger wtf in PHP is that '0' == FALSE, while any other non-empty string is true...



  •   OK I think I found it, the variables are used in a db query. The real WTF is the query: there is a (weird) prepared statement, but I can't see parameter binding before the query is executed...



  • @Evo said:

     I agree, this is not a wtf at all. A bigger wtf in PHP is that '0' == FALSE, while any other non-empty string is true...


    So it is in at least Perl and Javascript, for coercion reasons.



  • @Adriano said:

    @Evo said:

     I agree, this is not a wtf at all. A bigger wtf in PHP is that '0' == FALSE, while any other non-empty string is true...


    So it is in at least Perl and Javascript, for coercion reasons.

    What does '0' + 1 equal?

    How about 1 + '0'?



  • @Joeyg said:

    What does '0' + 1 equal?
    How about 1 + '0'?

    In both Perl and PHP, + is the mathematical addition operator, so both cases coerce '0' to 0 and result in 1. You'd need to use the . operator to get '10' and '01' - it coerces both operands into strings.

    In JS, + is overloaded to do both ops, but if either operand is a string, result is a string. Remaining math operators DO coerce into numbers, so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number. You can also use 1.0 (or 0.0) to promote variable to a floating point.



  • @Joeyg said:

    @Adriano said:
    @Evo said:

     I agree, this is not a wtf at all. A bigger wtf in PHP is that '0' == FALSE, while any other non-empty string is true...


    So it is in at least Perl and Javascript, for coercion reasons.

    What does '0' + 1 equal?

    How about 1 + '0'?

     

    Right, though it's important to remember what you're coercing to. In JavaScript, at least, "0" coerced to a boolean is true. "0" coerced to a number is 0, and 0 coerced to a boolean is false.



  • @bannedfromcoding said:

    You can also use 1.0 (or 0.0) to promote variable to a floating point.

    That's the usual way to create float constants in Ruby. Well that, or 1.to_f.



  • @bannedfromcoding said:

    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?



  • @blakeyrat said:

    @bannedfromcoding said:
    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?

     

    Without defending it, there are two possible explanations for this behavior:

    1. There was a time when people were obsessed with sending as few characters over the wire as possible. For short variable names, multiplying by 1 or subtracting 0 can be shorter than using Number().

    2. Historically, the majority of people who have written JavaScript for the web were very, very bad at it and were unaware of many standard features of the language.

    What bothers me is the idea that one should multiply something by 1.0 to convert it to floating point, when all numbers in JavaScript are floating point.



  • On my (weak) defense, I did not dabble in JS since a year or so.



  • @blakeyrat said:

    @bannedfromcoding said:
    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?

    Thanks. I have always used parseInt() and parseFloat(), but Number() looks much more sensible.

    (Having said that, I generally avoid processing in JS as much as possible. I have never been able to remember all its ludicrous type-conversion rules, as well as what types are returned from various functions.)



  • @Joeyg said:

    @blakeyrat said:
    @bannedfromcoding said:
    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?

    Thanks. I have always used parseInt() and parseFloat(), but Number() looks much more sensible.

    (Having said that, I generally avoid processing in JS as much as possible. I have never been able to remember all its ludicrous type-conversion rules, as well as what types are returned from various functions.)

    Well, if you're used to typecasting in C-type languages, and you're aware that JS only really has about 4 types: Boolean, Number, String, Object, then it's pretty easy to remember. My usual problem is that I try it lowercase, and get an error, then have to go back and capitalize it. There's also a String() function, for completeness sake.



  • @blakeyrat said:

    @Joeyg said:
    @blakeyrat said:
    @bannedfromcoding said:
    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?

    Thanks. I have always used parseInt() and parseFloat(), but Number() looks much more sensible.

    (Having said that, I generally avoid processing in JS as much as possible. I have never been able to remember all its ludicrous type-conversion rules, as well as what types are returned from various functions.)

    Well, if you're used to typecasting in C-type languages, and you're aware that JS only really has about 4 types: Boolean, Number, String, Object, then it's pretty easy to remember. My usual problem is that I try it lowercase, and get an error, then have to go back and capitalize it. There's also a String() function, for completeness sake.

    Yes, but Objects are created by the 'function' keyword - functions and objects are the same sorta thing (the equivalent of "classes" in prototype-based OO). But eval() and friends can take functions [i]or[/i] strings, Booleans and Numbers are (almost) always interchangable, and whenever one part of an expression becomes a String, it ruins the + operator and can often promote other parts of the expression to String. The last project I did, my boss told me that EMCAscript was "basically like Lisp", which helped me keep track of everything, though the next guy was [i]not[/i] impressed with the resulting code..



  • @Joeyg said:

    @blakeyrat said:
    @Joeyg said:
    @blakeyrat said:
    @bannedfromcoding said:
    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    It is? Like... among people who don't know about the Number() function?

    Thanks. I have always used parseInt() and parseFloat(), but Number() looks much more sensible.

    (Having said that, I generally avoid processing in JS as much as possible. I have never been able to remember all its ludicrous type-conversion rules, as well as what types are returned from various functions.)

    Well, if you're used to typecasting in C-type languages, and you're aware that JS only really has about 4 types: Boolean, Number, String, Object, then it's pretty easy to remember. My usual problem is that I try it lowercase, and get an error, then have to go back and capitalize it. There's also a String() function, for completeness sake.

    Yes, but Objects are created by the 'function' keyword - functions and objects are the same sorta thing (the equivalent of "classes" in prototype-based OO). But eval() and friends can take functions or strings, Booleans and Numbers are (almost) always interchangable, and whenever one part of an expression becomes a String, it ruins the + operator and can often promote other parts of the expression to String. The last project I did, my boss told me that EMCAscript was "basically like Lisp", which helped me keep track of everything, though the next guy was not impressed with the resulting code..

    See, I don't think of it that way. While a Function is an Object, it's also a String. If you type:

    function DoStuff( der ) { var i = der; };
    alert( DoStuff ) // notice no parens; I'm not executing the function, just referring to it

    You get a dialog box that reads: "function(der){ var i = der; };" That's all Eval is doing, when you pass it a Function.

    I've written JavaScript in the past that grabs the text of someone else's function using this method, makes some change to the function code, then replaces the old fuction with my new version. A simple case would be grabbing an existing JS function, replacing every occurrance of "alert(" to "handleErrors(", so that the code no longer alerts errors but displays them in a more friendly manner. I love that you can do this.

    Oh, also, you can also promote anything into an Object, just by giving it a property. If you're too lazy to type "var b = new Object(); b.hello = 'true';", you can just type "var b = ''; b.hello = 'true'" and you end up with the same thing.



  • @Joeyg said:

    But eval() and friends can take functions or strings,

    But you don't use eval(), and you will only use function refs in interval and timeout. If I catch you using eval(), you'll get a stern slapping of the forehead with a brick. Stop even mentioning eval().

    @Joeyg said:

    Booleans and Numbers are (almost) always interchangable

    But you don't use 'em that that way, normally. The only time I treat nums as bools is when getting data from HTML/XML, which is a string '0' or '1'. Don't use them interchangeably. No good comes of it. Be explicit.

    @Joeyg said:

    whenever one part of an expression becomes a String, it ruins the + operator and can often promote other parts of the expression to String.

    Add some parens or parseInts. It's not a difficult thing to control. It hardly bears mentioning unless you're a novice.

    @Joeyg said:

    my boss told me that EMCAscript was "basically like Lisp"

    Don't treat it like LISP. LISP is something else. Proficiency in one does not qualify you for the other.

    @Joeyg said:

    the next guy was not impressed with the resulting code..

    Might I be so presumptuous to say that you blame your boss' "tip" for messing up your own code?

    Some automatic type conversion is normally unwanted*. But it's not 'ludicrous' and all very easily understood and controlled. Its quirks are no graver crimes than any other language's.

     

    *)  Examples: the number 0 should convert to true, I think, because it's an existing
    number. If you want a bool, then Boolean() it. Also, parseInt('08') is a trap! because any number preceded with 0 is treated as octal.



  • @blakeyrat said:

    you can just type "var b = ''; b.hello = 'true'" and you end up with the same thing.
     

    SCHTOP!

    One thing I do think is something of a crminal quirk is that literal strings and numbers are not instantiated as objects.

    Your property b.hello remains undefined there.

    But, if you're too lazy to type new Object(), you can just type {} and get the same thing.

    You can even ridiculously over-engineer it like so:

    var b = {
       hello: 'true',
       toString: function () {
          return 'string content of b.'
       }
    }

    alert('this is the '+ b)

    Ain't it grand? (PROTIP: in case of coercion to string, JS will first look for a toString() method.)



  • @dhromed said:

    @Joeyg said:

    But eval() and friends can take functions or strings,

    But you don't use eval(), and you will only use function refs in interval and timeout. If I catch you using eval(), you'll get a stern slapping of the forehead with a brickdick. Stop even mentioning eval().




    FTFY



  • @dhromed said:

    @blakeyrat said:

    you can just type "var b = ''; b.hello = 'true'" and you end up with the same thing.
     

    SCHTOP!

    One thing I do think is something of a crminal quirk is that literal strings and numbers are not instantiated as objects.

    Your property b.hello remains undefined there.

    But, if you're too lazy to type new Object(), you can just type {} and get the same thing.

    This.

    JavaScript has object literals for a reason, and they're useful enough that they've been turned into a whole separate data interchange format that can be used by other languages.



  • @blakeyrat said:

    While a Function is an Object, it's also a String. If you type:

    function DoStuff( der ) { var i = der; };
    alert( DoStuff ) // notice no parens; I'm not executing the function, just referring to it

    You get a dialog box that reads: "function(der){ var i = der; };" That's all Eval is doing, when you pass it a Function

    @dhromed said:

    PROTIP: in case of coercion to string, JS will first look for a toString() method.
    I remember looking at the code of a Firefox addon where they patched the code of an incompatible addon by doing something like:

    <font face="courier new,courier">OtherAddon.func = new Function( OtherAddon.func.toString().replace('incompatible code', 'compatible code') );</font>



  • @dhromed said:

    @Joeyg said:

    But eval() and friends can take functions or strings,

    But you don't use eval(), and you will only use function refs in interval and timeout. If I catch you using eval(), you'll get a stern slapping of the forehead with a brick. Stop even mentioning eval().

    I think everybody in this thread should understand that we're talking about the quirks of a quirky language, and this is not a style guide.

    @dhromed said:

    @Joeyg said:

    whenever one part of an expression becomes a String, it ruins the + operator and can often promote other parts of the expression to String.

    Add some parens or parseInts. It's not a difficult thing to control. It hardly bears mentioning unless you're a novice.

    Or use the previously mentioned Number() and String() functions to force JavaScript to use the data type you want.

    @dhromed said:

    @Joeyg said:

    my boss told me that EMCAscript was "basically like Lisp"

    Don't treat it like LISP. LISP is something else. Proficiency in one does not qualify you for the other.

    See; that's the thing with JavaScript. It's "basically like LISP" but it's also "basically like C", "basically like BASIC", etc.

    It really needs to be considered its own language. It has some extremely powerful constructs, but it's not the same as "insert favorite language here."

    Anyway, how is it possible somebody has LISP experience but *not* JavaScript experience? WTF. "I've never used the extremely common language that every webpage uses, but I have a lot of experience in this academic language that's biggest claim to fame is running the Xerox Parc, a computer system that was never actually released."

    @dhromed said:

    SCHTOP!

    One thing I do think is something of a crminal quirk is that literal strings and numbers are not instantiated as objects.

    Your property b.hello remains undefined there.

    But, if you're too lazy to type new Object(), you can just type {} and get the same thing.

    You can even ridiculously over-engineer it like so:

    var b = {
    hello: 'true',
    toString: function () {
    return 'string content of b.'
    }
    }

    alert('this is the '+ b)
    Ain't it grand? (PROTIP: in case of coercion to string, JS will first look for a toString() method.)

    Yes, yes, I know, I know, sorry, sorry. Again: we're just playing with the language, not writing a style guide. Relax.

    (Although when I tested that in IE7, the property did indeed get set-- it didn't remain undefined-- so I think it must be an implementation detail. Or I read the debugger output wrong.)

    @someone you know said:

    This.

    JavaScript has object literals for a reason, and they're useful enough that they've been turned into a whole separate data interchange format that can be used by other languages.

    Ah, but most people use eval() on those. Barf.

    I'm actually a fan of JSON, but there needs to be something built into the language to convert the JSON string back into an object without doing anything potentially dangerous. The JSON parser at json.org is almost 10k, which is ridiculous.

    @zecc said:

    I remember looking at the code of a Firefox addon where they patched the code of an incompatible addon by doing something like:
    OtherAddon.func = new Function( OtherAddon.func.toString().replace('incompatible code', 'compatible code') );

    Yah, I mentioned doing that above. That used to break in older releases of Safari, BTW. Safari would give you some machine-crunched pre-processed function back when you asked for the function's .toString().



  • @dhromed said:

    @Joeyg said:

    But eval() and friends can take functions or strings,

    But you don't use eval(), and you will only use function refs in interval and timeout. If I catch you using eval(), you'll get a stern slapping of the forehead with a brick. Stop even mentioning eval().

    Oh, I know it. "eval() and friends" is how I describe the timeout functions, and even those make me nervous.

    @Joeyg said:

    Booleans and Numbers are (almost) always interchangable

    But you don't use 'em that that way, normally. The only time I treat nums as bools is when getting data from HTML/XML, which is a string '0' or '1'. Don't use them interchangeably. No good comes of it. Be explicit.

    @Joeyg said:

    whenever one part of an expression becomes a String, it ruins the + operator and can often promote other parts of the expression to String.

    Add some parens or parseInts. It's not a difficult thing to control. It hardly bears mentioning unless you're a novice.

    The point is that even when I [i]am[/i] being explicit, every so often I slip up and a type gets promoted in an insane way without my noticing. There's no other language in which that has happened to me. I don't think it's happened to me in a number of years, but early experience (and some truly awful "Javascript" books as a child) (you can imagine the sort) have made me always on edge while using the language.

    @Joeyg said:

    my boss told me that EMCAscript was "basically like Lisp"

    Don't treat it like LISP. LISP is something else. Proficiency in one does not qualify you for the other.

    @Joeyg said:

    the next guy was not impressed with the resulting code..

    Might I be so presumptuous to say that you blame your boss' "tip" for messing up your own code?

    Oh, no, the real reason my code was crap was much worse :) my boss wanted me to drop all the jQuery because he didn't trust it (and with good reason - the guy who had implemented it somehow used it to slow the site by 50 times, and wrapped it up in dozens of SQL vulnerabilities, and globally scoped every variable, and generally made the whole codebase an unreadable mess). It was easy enough to drop it and rewrite the entire site - its functionality was simple enough, anyway - and add in all the original useful features. ie, you could double-click text fields to edit them if you were an administrator, but if you tried to select text it would no longer start folding and unfolding crap and wrecking the site layout.

    That was also fine, because it was still pretty easy Javascript, even without a library. But the problem was that the code was way faster, looked better, behaved correctly, handled edge cases, handled permissions and was quite a bit easier to use for all that. [b]And[/b] the CEO (this was a small company, but he was a [i]big[/i] douche) called me up and realized that I could change stuff and extend features while he was talking to me. The last guy would start to whine and blubber and insist these things were impossible, then take up 12 hours of my boss's time demanding help for the tiniest things. And the result would be an impossible pile of crap. Sadly, I destroyed all of the old code when I was done and ran away from the company (who I think has backups), or I'd show it to you guys.

    At this point, my boss was free to work on the backend and implement all his insane ideas - this company was not a pyramid scheme, per se, but they never quite convinced [i]me[/i] of that - so that should give you an idea about how he thought of cash and stock. (We did have [i]stock[/i], by the way - we filled an entire abandoned leaky mall with old shit and we were working in the spaces between the shit. So in that respect we weren't just pyramid-ing money. There were sales happening. It was weird. I tried to learn as little as possible, for liability reasons.) Meanwhile, the CEO thought I was the smartest programmer I had ever met. In fact, I had only ever done Javascript according to my rules:

    1. It had better be accessible. [b]Period.[/b] No javascript links or sound clips or "unhiding" things that should never have been hidden.

    2. It had better work if Javascript is disabled. Or broken. Period.

    3. It had better not get in the way or be irritating. If possible, the user shouldn't have to know or care about it. Don't override clicks on [i]any[/i] UI component, and don't override right-clicks. Double-clicks are usually okay, except that that's how people select text, so try not to even do that.

    Assuming I stuck with these rules, I would be okay even though I'm no Javascript expert (hell, I don't claim to [i]know[/i] Javascript unless directly asked). However, needless to say, my CEO thought all of these rules were stupid and unnecessary, and would spent four consecutive hours on Skype each day trying to micromanage me into breaking them all. And since most of what he was suggesting would only affect administrators, I couldn't complain about it - after all, it's not like real users will see this shit. How bad can it be?

    The my boss jumped on and started suggesting I do things to the front end that the last guy couldn't even imagine. I rewrote the search page to actually search items, I implemented Back/Forward buttons that actually remembered the search results, I implemented a "back to search" button that could figure out which page of results you had backed/forwarded to, I wrote a checkout system even though I had never touched written e-commerce code in my life, plus a ton of other little stuff regarding item listings and display and aggregating and blah blah blah. Also I redid the entire database schema - which again, wasn't too complicated, but was absolutely [b]filled[/b] with cruft - and ported it from MySQL to Postgres (which was good, except I had never used Postgres in my life). And I did all this to the best of my understanding of his "grand vision" for the site, or the company, or whatever he was getting at. Ironically, the Lisp tip helped me out more than anything here.

    [i]And even then[/i], I might have been okay. Except I had six weeks to do it. That was when I was going back to school, and I was ready for [i]any[/i] excuse to run away from this company. (Later I deleted them from my resume, so it turned out I didn't need an excuse, but c'est la vie.) So I did all this in six weeks, with constantly-changing requirements, 4-6 hours of Skype each day, no clue what the company or I was doing. But they all thought I was fucking brilliant, and I got a raise every day for the last week as they begged me to stay, so I did it.

    The net result wasn't too bad, as I recall. There were a lot of callbacks and prototypes, which often scare people who don't know Javascript that well, but other than that I thought it was okay. But I talked to the guy after me and he said he was "slowly redoing it all" and that there was a lot of "creative stuff he'd never seen before". I don't know if he was the idiot or I was, but given the above story, I'm pretty sure I was to blame. This is the first time I've admitted to writing that code.

    Some automatic type conversion is normally unwanted*. But it's not 'ludicrous' and all very easily understood and controlled. Its quirks are no graver crimes than any other language's.

     

    *)  Examples: the number 0 should convert to true, I think, because it's an existing number. If you want a bool, then Boolean() it. Also, parseInt('08') is a trap! because any number preceded with 0 is treated as octal.

    I'm an embedded developer. 0 to me is all-bits-zero, which is also how false (and usually NULL) is represented. I'm happy for it to be equivalent to true - it's just not as intuitive to me.

    But if true might then also become "true" or 1 or even "1" depending on what happens to it, when it started as "0", that's when things start to get scary. Especially when I asked the user (or backend, or frontend) for a numeric 0 and get a string "0". And every so often I find a browser who uses a different type. Or maybe I'm just imagining that. I dunno.

    But again, my Javascript philosophy involves doing as little of it as possible. So I'm not one to talk.



  • @Joeyg said:

    my life
     

    There, there. :)

    @Joeyg said:

    even those make me nervous.

    As long as you only use function refs for them, not strings, then it really gets a lot better. You do have to take into account that this function is executed context-free in global scope, but eh.

    @Joeyg said:

    I'm an embedded developer.

    Do you have a filesystem?

    @Joeyg said:

    when I asked the user (or backend, or frontend) for a numeric 0 and get a string "0".

    On the web, there's no way you can get anything from the user but a string. That's how GET and POST work. If you ask for 0, you will always get "0". 

     @Joeyg said:

    my Javascript philosophy involves doing as little of it as possible.

    So does mine, actually. I think gmail is an abomination, regardless of whether it works. Javascript was not designed for that kind of crap. gmail is the only reason my firefox eats almost 300MB RAM* Then again, if the browser can make it work, :shrug.

     

    ) on XP*.

     

     **) yeah, still on XP. :<br>



  • Now I'm no fan of gmail*, but RIA is only going to become more and more expected. Now if gmail is really using a sizable chunk of that 300MB then I am sure that in time they will switch over to local storage. If the 300MB is just firefox being hungry, then blame firefox.

     

    * their IMAP is more like IMAP-ish.



  • @bannedfromcoding said:

    so it's a common idiom to use var - 0, var * 1, or var / 1 to convert string to number.

    There's the "unary plus" too; +var converts a string to a number too. Of course, Number() or parseInt() or something would be better.



  • @Kiss me I'm Polish said:

      OK I think I found it, the variables are used in a db query. The real WTF is the query: there is a (weird) prepared statement, but I can't see parameter binding before the query is executed...

    That's because there's no parameter binding, because there's no parameters (in the DB query sense, at least).  This is using a prepare statement, but it's still building a static string which is subject to injection attacks.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.