views:

512

answers:

9

(This question uses PHP as context but isn't restricted to PHP only. e.g. Any language with built in hash is also relevant)

Let's look at this example (PHP):

function makeAFredUsingAssoc()
{
    return array(
        'id'=>1337,
        'height'=>137,
        'name'=>"Green Fred");
}

Versus:

class Fred
{
    public $id;
    public $height;
    public $name;

    public function __construct($id, $height, $name)
    {
        $this->id = $id;
        $this->height = $height;
        $this->name = $name;
    }
}

function makeAFredUsingValueObject()
{
    return new Fred(1337, 137, "Green Fred");
}

Method #1 is of course terser, however it may easily lead to error such as

$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here

Of course, one might argue that $myFred->naem will equally lead to error, which is true. However having a formal class just feels more rigid to me, but I can't really justify it.

What would be the pros/cons to using each approach and when should people use which approach?

A: 

I prefer to have hard-coded properties like in your second example. I feel like it more clearly defines the expected class structure (and all possible properties on the class). As opposed to the first example which boils down to just always remembering to use the same key names. With the second you can always go back and look at the class to get an idea of the properties just by looking at the top of the file.

You'll better know you're doing something wrong with the second one -- if you try to echo $this->doesntExist you'll get an error whereas if you try to echo array['doesntExist'] you won't.

Parrots
Actually, you'll get a `NOTICE` of `PHP Notice: Undefined index: doesntExist`
cballou
Sorry, right, you'll get a notice, but that's a lot harder to find sometimes than the page outright breaking. That can go unnoticed for a while (no pun intended).
Parrots
+1  A: 

When the return value represents an entity in your application, you should use an object, as this is the purpose of OOP. If you just want to return a group of unrelated values then it's not so clear cut. If it's part of a public API, though, then a declared class is still the best way to go.

Will Vousden
I tried very hard and failed to think of a practical scenario where I would want to return a group of unrelated values. Maybe when reading a CSV but PHP's fgetcsv() gives a numeric array anyway, so...
kizzx2
+3  A: 

Under the surface, the two approaches are equivalent. However, you get most of the standard OO benefits when using a class: encapsulation, inheritance, etc.

Also, look at the following examples:

$arr['naem'] = 'John';

is perfectly valid and could be a difficult bug to find.

On the other hand,

$class->setNaem('John');

will never work.

Zack
+1. Once you get rid of the public member variables, the advantage of the class becomes clear.
Frank Farmer
+2  A: 

Let me pose this question to you:

What's so different about making a typo like $myFred['naem'] and making a typo like $myFred->naem? The same issue still exists in both cases and they both error.

I like to use KISS (keep it simple, stupid) when I program.

  • If you are simply returning a subset of a query from a method, simply return an array.
  • If you are storing the data as a public/private/static/protected variable in one of your classes, it would be best to store it as a stdClass.
  • If you are going to later pass this to another class method, you might prefer the strict typing of the Fred class, i.e. public function acceptsClass(Fred $fredObj)

You could have just as easily created a standard class as opposed to an array if it is to be used as a return value. In this case you could care less about strict typing.

$class = new stdClass();
$class->param = 'value';
$class->param2 = 'value2';
return $class;
cballou
Any reason why anyone would prefer to use stdClass instead of an assoc. array? Their function looks pretty much the same to me. The assoc. array syntax is much clearer and simpler.
kizzx2
@kizz - mainly when you need to store an array of objects for easier iteration, much how database abstraction layers return an array of objects (with each object representing a row).
cballou
A: 

A pro for the hash: It is able to handle name-value combinations which are unknown at design time.

Veger
So can a class. If you just instantiate a class and then do something like $class->madeup = 'hello'; echo $class->madeup; It will echo 'hello' :) (of course this work when using php classes not sure on other languages)
AntonioCS
Hm... you are right. This would be supported in all dynamic languages which allow modifications to classes at run-time. There goes the pro for using hashes...
Veger
A: 

Depending on the UseCase I might use either or. The advantage of the class is that I can use it like a Type and use Type Hints on methods or any introspection methods. If I just want to pass around some random dataset from a query or something, I'd likely use the array. So I guess as long as Fred has special meaning in my model, I'd use a class.

On a sidenote:
ValueObjects are supposed to be immutable. At least if you are refering to Eric Evan's definition in Domain Driven Design. In Fowler's PoEA, ValueObjects do not necessarily have to be immutable (though it is suggested), but they should not have identity, which is clearly the case with Fred.

Gordon
A: 

Honestly, I like them both.

  • Hash arrays are way faster than making objects, and time is money!
  • But, JSON doesn't like hash arrays (which seems a bit like OOP OCD).
  • Maybe for projects with multiple people, a well-defined class would be better.
  • Hash arrays might take more CPU time and memory (an object has a predefined amount), though its hard to be sure for every scenario.

But what really sucks is thinking about which one to use too much. Like I said, JSON doesn't like hashes. Oops, I used an array. I got to change a few thousand lines of code now.

I don't like it, but it seems that classes are the safer way to go.

Josh
+1  A: 

A simple class like this one:

class PersonalData {
    protected $firstname;
    protected $lastname;

    // Getters/setters here
}

Has few advantages over an array.

  1. There is no possibility to make some typos. $data['firtsname'] = 'Chris'; will work while $data->setFirtsname('Chris'); will throw en error.
  2. Type hinting: PHP arrays can contain everything (including nothing) while well defined class contains only specified data.

    public function doSth(array $personalData) {
        $this->doSthElse($personalData['firstname']); // What if "firstname" index doesn't exist?
    }
    
    
    public function doSth(PersonalData $personalData) {
        // I am guaranteed that following method exists. 
        // In worst case it will return NULL or some default value
        $this->doSthElse($personalData->getFirstname());
    }
    
  3. We can add some extra code before set/get operations, like validation or logging:

    public function setFirstname($firstname) {
        if (/* doesn't match "firstname" regular expression */) {
            throw new InvalidArgumentException('blah blah blah');
        }
    
    
    
    if (/* in debbug mode */) {
        log('Firstname set to: ' . $firstname);
    }
    
    
    $this->firstname = $firstname;
    
    }
  4. We can use all the benefits of OOP like inheritance, polymorphism, type hinting, encapsulation and so on...
  5. As mentioned before all of our "structs" can inherit from some base class that provides implementation for Countable, Serializable or Iterator interfaces, so our structs could use foreach loops etc.
  6. IDE support.

The only disadvantage seems to be speed. Creation of an array and operating on it is faster. However we all know that in many cases CPU time is much cheaper than programmer time. ;)

Crozin
I totally agree in particular with #2. It inspired my own answer below.
kizzx2
A: 

After thinking about it for some time, here's my own answer.

The main thing about preferring value objects over arrays is clarity.

Consider this function:

// Yes, you can specify parameter types in PHP
function MagicFunction(Fred $fred)
{
    // ...
}

versus

function MagicFunction(array $fred)
{
}

The intent is clearer. The function author can enforce his requirement.

More importantly, as the user, I can easily look up what constitutes a valid Fred. I just need to open Fred.php and discover its internals.

There is a contract between the caller and the callee. Using value objects, this contract can be written as syntax-checked code:

class Fred
{
    public $name;
    // ...
}

If I used an array, I can only hope my user would read the comments or the documentation:

// IMPORTANT! You need to specify 'name' and 'age'
function MagicFunction(array $fred)
{
}
kizzx2