5

I should add out by saying that while KVP-arrays work fine, I prefer objects when doing OOP as $foo->bar->foo just seems cleaner than $foo->bar['foo'] in my opinion.

PHP has a great way of creating arrays with pre-populated data through $foo = array('foo' => 'bar'); or even the new 5.4 bracket syntax: $foo = ['foo' => 'bar'], but the same syntax does not seem to exist for objects (stdClass).

Array demo:

<?php
    class Foo {
        public $bar = array(
            'foo' => 'bar',
            'bar' => 'foo'
        );
    }

    $foo = new Foo;
    var_dump($foo->bar);
    /*
        array(2) {
          ["foo"]=>
          string(3) "bar"
          ["bar"]=>
          string(3) "foo"
        }
    */
?>

Great - what if we want to do the same with objects without using a __construct?


Try #1 - casting to object - nope; we can't cast in the declaration of a class variable:

<?php
    class Foo {
        public $bar = (object)array(
            'foo' => 'bar',
            'bar' => 'foo'
        );
    }

    /*
        Parse error: syntax error, unexpected T_OBJECT_CAST on line 4
    */
?>

Try #2 - using json_decode and json_encode - nope; we can't call functions in the declaration of a class variable:

<?php
    class Foo {
        public $bar = json_decode(json_encode(array(
            'foo' => 'bar',
            'bar' => 'foo'
        )));
    }

    /*
        Parse error: syntax error, unexpected '(', expecting ',' or ';' on line 3
    */
?>

Try #3 - using javascript style brackets - nope; even though []'s were added in PHP 5.4, object brackets still do not exist*:

*rfc for array brackets

<?php
    class Foo {
        public $bar = {
            'foo' => 'bar',
            'bar' => 'foo'
        };
    }

    /*
        Parse error: syntax error, unexpected '{' on line 3
    */
?>

The only way that seems to work is by using a __construct and converting the KVP-array to an object, but it just seems completely backwards to declare a variable as one thing, and before we ever use it, cast it to something else.

__construct demo:

<?php
    class Foo {
        public $bar = array(
            'foo' => 'bar',
            'bar' => 'foo'
        );

        public function __construct() {
            $this->bar = (object)$this->bar;
        }
    }

    $foo = new Foo;
    var_dump($foo->bar);
    /*
        object(stdClass)#2 (2) {
          ["foo"]=>
          string(3) "bar"
          ["bar"]=>
          string(3) "foo"
        }
    */
?>

  • Is there some short-hand syntax I haven't been able to find?
  • If not; is it going to be added in future PHP versions?
  • If not/until then; Is there a better way than having to add __construct's every single time?
  • Should I, instead, just deal with the fact that using an array in this situation is better, even though, in my opinion, it seems messier?

Why?:

Working on a new DB class for a company, I've had to resort to the current code in order to manage saving DB credentials for further inspection later in the code. Of course a different design pattern, such as $connectionHost, $connectionDatabase, etc. would work fine - but it seems cluttered to me.

Example:

<?php
    class DB {
        public $connection = array(
            'host'     => null,
            'database' => null,
            'user'     => null,
            'engine'   => null
        );
        public function __construct($host, $database, $user, $engine = 'mysql') {
            //Essentially I'd like the following line not to be needed:
            $this->connection = (object)$this->connection;

            $this->connection->host     = $host;
            $this->connection->database = $database;
            $this->connection->user     = $user;
            $this->connection->engine   = $engine;
        }
    }

    $db = new DB('127.0.0.1', 'server_db', 'my_user');
    var_dump($db->connection->host);
?>

http://codepad.org/vwy1y9NP

9
  • Why are you mixing objects and data to begin with? A line like $foo->foo['bar'] should set off some alarm bells. Something to keep in mind is that objects are considerably slower than arrays. Commented Jul 30, 2013 at 15:54
  • Interesting question, but agree with the concern that you shouldn't be doing this. Commented Jul 30, 2013 at 15:57
  • 1
    Objects are considered dynamic information and you cannot declare properties with dynamic information. Commented Jul 30, 2013 at 15:59
  • @FritsvanCampen I've added my test case to the OP. Commented Jul 30, 2013 at 16:00
  • 1
    @Gordon The second link (not the marked as duplicate link) describes the possibility of simply casting it as an object, which you just can't do when declaring it as a class property. The first link refers to objects which are parsed through (unlike the actual use-case in the bottom of the OP - specifying these as strings wouldn't make a difference, and the only way to cast it would be to call the class constructor as new Foo(array('foo' => 'bar'));, and then I might as well cast it to an object there. "There isn't" is what I wanted to make sure of, so thank you. Commented Jul 30, 2013 at 16:12

1 Answer 1

1

Yep, stick with an array. There's no shorthand way of declaring an object. But you CAN directly assign nested properties, if you absolutely have to, without instantiating the intermediate objects yourself:

php > $x = new StdClass;
php > $x->foo->bar = 'baz';
php > var_dump($x);
object(stdClass)#2 (1) {
  ["foo"]=>
  object(stdClass)#1 (1) {
    ["bar"]=>
    string(3) "baz"
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

In that specific case, you could one-liner it: $x = (object)array('foo' => (object)array('bar' => 'baz')); - it's just incredibly messy, and you still can't use the new keyword when declaring class constants unless used in a __construct. Disclamer: I wasn't the one who down-voted you.
Yes, this'd only be useful if all you're using the object for is as a data storage structure.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.