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

h2ooooooo
  • 39,111
  • 8
  • 68
  • 102
  • 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. – Halcyon Jul 30 '13 at 15:54
  • Interesting question, but agree with the concern that you shouldn't be doing this. – Jason McCreary Jul 30 '13 at 15:57
  • 1
    Objects are considered dynamic information and you cannot declare properties with dynamic information. – Gordon Jul 30 '13 at 15:59
  • @FritsvanCampen I've added my test case to the OP. – h2ooooooo Jul 30 '13 at 16:00
  • Also [Does PHP feature short hand syntax for objects](http://stackoverflow.com/questions/455800/does-php-feature-short-hand-syntax-for-objects) – Gordon Jul 30 '13 at 16:04
  • @Gordon Both of those are different use-cases. The latter being outside a class, as you can't cast when declaring as a class property. (Test case #1) – h2ooooooo Jul 30 '13 at 16:05
  • @h2ooooooo what are different use-cases? You asked for a way to declare a property with an object. That's not possible. And it explains so in the dupe. The second link just answers whether there is any shorthand syntax for objects. There isn't. So the answers to your question are: No. Unlikely. No. Yes. – Gordon Jul 30 '13 at 16:08
  • 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. – h2ooooooo Jul 30 '13 at 16:12
  • FWIW, as long as you are stuck having to make a constructor, I think its cleaner to move the entire initialization into constructor: `public $bar; ... public function __construct() { $this->bar = (object){ 'foo' => 'bar', 'bar' => 'foo' }; ...` – ToolmakerSteve Mar 06 '19 at 23:01

1 Answers1

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"
  }
}
Marc B
  • 356,200
  • 43
  • 426
  • 500
  • 1
    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.* – h2ooooooo Jul 30 '13 at 16:02
  • Yes, this'd only be useful if all you're using the object for is as a data storage structure. – Marc B Jul 30 '13 at 16:03