Casted fun.

In the German channel #php.de/IRCNet people discuss every kind of stuff. Sometimes there are even discussions about PHP related topics. Today we had a discussion about having fun with casting in PHP.

My colleague Uwe asked wether PHP already supports object casting. Object casting could be used to convert an object returned from some function to an object from an extended class:

  1. <?php 
  2. class Bar
  3.  /* ... */ 
  4.  
  5. class Foo extends Bar
  6.  /* ... */ 
  7.  
  8. function do_something() { 
  9.     return new Bar(); 
  10.  
  11. $bar = do_something(); 
  12. $foo = (Foo)$bar
  13. ?>

Now $foo would be an object of the Foo class but such a casting is not (yet) supported by PHP. Nasty ideas to simulate it (Decorator pattern, classkit or some serialize-manipulate-unserialize-magic) didn’t please him.

As used from other places such discussions won’t stop then but develop into other directions. But taking a look at PHP casting options someone found the object cast operator. It can be used to convert some variable to a stdClass object. If the variable is a scalar the object gets a property "scalar" with the original value:

$ php -r '$a = 1; var_dump((object)$a);'<br />object(stdClass)#1 (1) {<br />  ["scalar"]=><br />  int(1)<br />}<br />

If you cast an array you get a stdClass object with the array’s keys as value:

$ php -r '$a = array("a" => 23, "b" => 42); var_Dump((object)$a);'<br />object(stdClass)#1 (2) {<br />  ["a"]=><br />  int(23)<br />  ["b"]=><br />  int(42)<br />}

This is followed by the question what happens with numeric keys since numbers aren’t valid property name? – Quite simple nothing special:

$ php -r '$a = array(23, 42); var_dump((object)$a);'<br />object(stdClass)#1 (2) {<br />  [0]=><br />  int(23)<br />  [1]=><br />  int(42)<br />}<br />

Now we have properties with integers as their name. Accessing them with $a->0 gives a parse error since this syntax isn’t allowed, but PHP offers another syntax for this: $a->{0} This even works for strings with invalid characters, like spaces or other weird stuff:

$ php -r '$a = array("    #<>" => 42); $b = (object)$a; echo $b->{"    #<>"};'<br />42

This is fun but that’s not everything you can do with PHP’s casting syntax: PHP does even support an unset cast operator (unset). The array to object cast might sometimes make sense but we have no clue why a cast to unset is needed.

$ php -r '$bar = 1; $foo = (unset)$bar; var_dump(isset($foo));'<br />bool(false)

Now $foo is unset but $bar is still 1. Using unset() on a variable makes sense but casting some value to unset? Is it just a strange way to do unset($foo);?

But i am curious: Please leave a comment if you can think of an situation where (unset) might actually make sense.

Für neue Blogupdates anmelden:


10 Gedanken zu “Casted fun.

  1. That’s some nice gimmicks you found there.

    I’m interested in why that guy wanted to downcast his object. Since PHP is a loosely typed language, featuring arrays in which you can put just everything without worrying about consistency, I can’t think of a single scenario to downcast objects.

      • I do understand the concepts of OOP and know that in >95% of the cases downcasting is used to regain type information an object lost when getting pushed into some sort of multitype-container which is making use of subtyping polymorphism parametrized by it’s elementen’s common abstract class.

        PHP already has all-in-one arrays suitable for every purpose (for you, my German friend: ‚Eierlegende Wollmilchsau-Arrays‘), which don’t care what types of data you insert (as a matter of fact, they _must_ not care, since PHP is dynamically typed and by definition lacks type safety). Hence, there is no need for up- or downcasting.

        Your post is not only ignorant but also rude and [x]childish. Maybe you should check out the heise.de forums and flame on over there with equally clueless and unmannered people.

        • ok, I’m sorry and apologize for rudeness.

          it was just surprising for me that noone – even me – did/does not miss it.

          it was just a „why is it not in php“-question, just like operator overloading (see johannes schlueter’s patch).

          i needed only for a second, then solved my problem another way.

          best regards
          uwe

        • Hi Marten,

          I am used to work with downcasting in c#/delphi quite often. I would expect that a simple array-cast won’t work in 50% of all cases, since the derived classes add some functionality.

          With PHProjekt we have a groupware and a example were downcasting would actually make sense:

          class CalendarEntry extends the base class Entry, which does the rights-management, objecthandling and contains the metadata.

          CalendarEntry would offer some methods like addRepeatingException – where a (array) cast can’t help.

          So you basically you are right, i just would expect a higher percentage of needing more than just the data.

          BTW. a typecast of an instance of

          class myClass {
          private $_priv = ‚bla‘;
          protected $_prot = ‚bla‘;
          public $pub = ‚bla‘;
          }

          results in

          [„myclass_priv“]=>
          string(3) „bla“
          [„pub“]=>
          string(3) „bla“
          [„*_prot“]=>
          string(3) „bla“

          best regards,
          Johann

          • Johann,

            I can’t see what you’re going for. If you think that the 95% thingie is wrong, you’re probably right. Your example, however, doesn’t make sense to me.

            In PHP, if you have an Entry and a CalendarEntry, I can’t think of a reason to address the CalendarEntry instance as an Entry one. PHP does not care about arguments‘ data types. That’s why it doesn’t support specifying them in signatures in the first place (aside from the type hint hack but that’s another subject).

            Let’s say EntryHandler fetches and dispatches all sorts of Entries. In C++, Java, etc. you’d need a) overloading or b) subtyping to achieve polymorphism, whereas the latter one is the way to go in this case. You’d have to specify as your argument’s data type – which would make you lose type information. To use addRepeatingException within (or after) the dispatching method you’d have to downcast.

            In contrast PHP scripts can decide at runtime wheter the argument’s data type is suitable or not. No upcasting, no downcasting, no problems.

            The PHP downcasting shown in this article is by the way horrible, I would never consider using it. My point is that one should never have to up-/downcast in PHP at all. :)

  2. What i meant: „You’d have to specify *Entry* as your argument’s data type – which would make you lose type information.“

    The comment system stripped the *Entry* because it it looked like a HTML tag I guess.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.