Stuart
Stuart

Reputation: 3258

Creating Object instance from Posted data - PHP

What is the best way of creating and populating an Object from values passed in from a form?

If for example, i have a class Car with properties Colour, Model, Make, Year and a method Save, which will either insert or update the record.

I then have a form that has fields for all these values and it is submitted. I want to create an instance of class Car with the posted values and then call the Save method. All good and well.

But what is the best way of assigning the posted values to the objects internal properties. Assuming this is a simplified scenario and the actual situation would have many more properties, making individual Set calls long-winded.

Is it best to simply call the Set method for each one? Or pass in an array to a method (or the constructor) which then calls the Set methods? Or some other way?

Any advice on best practices is appreciated

Cheers Stuart

Upvotes: 8

Views: 11036

Answers (6)

soulmerge
soulmerge

Reputation: 75704

I would implement the magic function __set_state(), as it is intended for exactly this use case. There are multiple benefits of putting the implementation into that method:

  1. It is very well defined, what this function does (It is defined in the PHP docs, in contrast to your own source code)
  2. You can access private members within the function
  3. Objects dumped with var_export() will be automatically reconstructed using this function.

EDIT As requested in the comments:

class A {
    private $member = 1000;
    public static function test(A $a) {
        echo $a->member;
    }
}
echo A::test(new A()); // outputs 1000

EDIT Fulfilling another request from the comments:

You cannot know on which class a static method was called unless you are using php 5.3, in which the required feature (late static binding) was introduced. What you can do in emulating get_called_class() by analyzing the current stack (using debug_backtrace()). If you have a working get_called_class() function, you can do the following:

class BaseClass {
    public static function __set_state($state) {
        $class = get_called_class();
        // Assumption: Constructor can be invoked without parameters!
        $object = new $class();
        foreach (get_class_vars($class) as $member) {
            if (!isset($state[$member])) {
                // Member was not provided, you can choose to ignore this case
                throw new Exception("$class::$member was not provided");
            } else {
                // Set member directly
                // Assumption: members are all public or protected
                $object->$member = $state[$member];
                // Or use the setter-approach given by Chaos.
                $setter = 'set' . ucfirst($member);
                $object->setter($state[$member]);
            }
        }
        return $object;
    }
}

Upvotes: 2

Ateş Göral
Ateş Göral

Reputation: 140050

In case the object that you're posting may become more complex than a flat list of properties in the future (think nesting, arrays as values etc.), you could first create a JavaScript object on the client side and post it as JSON inside a single parameter. Then you can simply deserialize the JSON string into a PHP object. PHP 5+ has built-in support for JSON deserialization. Using JSON would allow you to be flexible in how complex your object can be.

Upvotes: 1

Davide Gualano
Davide Gualano

Reputation: 13003

You can use a bit of Reflection magic:

public function loadFromArray($array) {
    $class = new ReflectionClass(get_class($this));
    $props = $class->getProperties();
    foreach($props as $p) {
         if (isset($array[$p->getName()])
              $p->setValue($this, $array[$p->getName]);
    }
}

You can implement this method in a base class and make all yout object inherit from that, so you have this functionality in every object without repeating yourself in any class.

Upvotes: 6

knittl
knittl

Reputation: 265231

create a constructor which will take all the attributes

class Car {
  // private members …
  public function __construct($color, $type, $model, $make) {
    // assign your values here
  }
  // other methods
};

if you are dealing with associative arrays, you can also use a constructor with an array as argument:

public function __construct($car_properties) {}

and then loop your properties with

foreach($car_properties as $property => $value) {
  if(isset($value)) $this->property = $value
}

be sure to sanitize/validate your input beforehand! (can’t stress this often enough)

Upvotes: 0

Rik Heywood
Rik Heywood

Reputation: 13972

Well, you can convert the post array to an object in one step...

$mypostobject = (object) $_POST;
echo $mypostobject->Colour;

EDIT: added link to PHP docs. http://uk.php.net/manual/en/language.types.object.php

If you want to do this with your own class of object, then some kind of constructor or function that takes the post array and set up your class would be in order.

class MyCar {
  public function __construct($postdata) 
  {
    $this->Colour = $postdata['Colour'];
    // etc
  }
};

$car = new MyCar($_POST);

Upvotes: 1

chaos
chaos

Reputation: 124297

If the properties are public:

foreach($_POST as $key => $value)
    $obj->$key = $value;

If they require setters:

foreach($_POST as $key => $value) {
    $set = 'Set' . $key;
    $obj->$set($value);
}

Upvotes: 6

Related Questions