从发布的数据创建对象实例-PHP

从发布的数据创建对象实例-PHP,php,oop,Php,Oop,从表单传入的值创建和填充对象的最佳方法是什么 例如,如果我有一辆带有属性颜色、型号、品牌、年份和方法保存的class Car,它将插入或更新记录 然后,我有一个表单,其中包含所有这些值的字段,并将其提交。我想用发布的值创建一个类Car的实例,然后调用Save方法。一切都很好 但是,将发布的值指定给对象内部属性的最佳方式是什么。假设这是一个简化的场景,而实际情况会有更多的属性,使得单个集合调用变得冗长 是否最好只为每个方法调用Set方法?或者将数组传递给方法(或构造函数),然后该方法调用Set方法

从表单传入的值创建和填充对象的最佳方法是什么

例如,如果我有一辆带有属性颜色、型号、品牌、年份和方法保存的class Car,它将插入或更新记录

然后,我有一个表单,其中包含所有这些值的字段,并将其提交。我想用发布的值创建一个类Car的实例,然后调用Save方法。一切都很好

但是,将发布的值指定给对象内部属性的最佳方式是什么。假设这是一个简化的场景,而实际情况会有更多的属性,使得单个集合调用变得冗长

是否最好只为每个方法调用Set方法?或者将数组传递给方法(或构造函数),然后该方法调用Set方法?还是其他方式

任何关于最佳实践的建议都将不胜感激

干杯
斯图尔特

我将实现这个神奇的功能,因为它正是为这个用例而设计的。将实现应用到该方法中有多种好处:

  • 这个函数的定义非常好(它是在PHP文档中定义的,与您自己的源代码不同)
  • 您可以访问函数中的私有成员
  • 使用此函数将自动重建转储的对象
  • 根据评论中的要求编辑

    class A {
        private $member = 1000;
        public static function test(A $a) {
            echo $a->member;
        }
    }
    echo A::test(new A()); // outputs 1000
    
    编辑满足评论中的另一个请求:

    class A {
        private $member = 1000;
        public static function test(A $a) {
            echo $a->member;
        }
    }
    echo A::test(new A()); // outputs 1000
    
    除非您使用的是PHP5.3,其中引入了必需的特性(),否则您无法知道在哪个类上调用了静态方法。您可以通过分析当前堆栈(使用)来模拟
    get_called_class()
    。如果您有工作功能,可以执行以下操作:

    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;
        }
    }
    

    如果属性是公共的:

    foreach($_POST as $key => $value)
        $obj->$key = $value;
    
    如果需要设置器:

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

    好吧,你可以一步把post数组转换成一个对象

    $mypostobject = (object) $_POST;
    echo $mypostobject->Colour;
    
    编辑:添加了到PHP文档的链接

    如果您想对自己的对象类执行此操作,那么需要某种构造函数或函数来获取post数组并设置您的类

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

    创建一个将接受所有属性的构造函数

    class Car {
      // private members …
      public function __construct($color, $type, $model, $make) {
        // assign your values here
      }
      // other methods
    };
    
    如果要处理关联数组,还可以使用带有数组作为参数的构造函数:

    public function __construct($car_properties) {}
    
    然后使用

    foreach($car_properties as $property => $value) {
      if(isset($value)) $this->property = $value
    }
    
    请务必事先对您的输入进行消毒/验证!(不能经常强调这一点)

    你可以使用一些魔法:


    您可以在基类中实现此方法,并使所有yout对象继承自该基类,这样您就可以在每个对象中使用此功能,而无需在任何类中重复自己的操作。

    如果您发布的对象将来可能变得比单一属性列表更复杂(将嵌套、数组视为值等),您可以首先在客户端创建一个JavaScript对象,并将其作为JSON发布到单个参数中。然后,您可以简单地将JSON字符串反序列化为PHP对象。PHP5+内置了对JSON反序列化的支持。使用JSON可以让您灵活地了解对象的复杂程度。

    我认为此方法的实现将与上面Chaos的建议(接近)完全相同吗?是的,实现将是相同的。扩展的答案解释了我为什么建议这种方法。你确定你可以访问私人成员吗__set_state应该是静态函数,$这里没有定义,而是创建一个新的对象实例,然后给它分配变量。因此,请解释如何从函数中访问私有变量?
    private
    成员可以从定义它们的类中的任何地方访问,如果需要,您可以编写一些测试代码。您无法访问的唯一私有成员是继承的成员。不能从静态uuu set_state函数访问私有成员,因为$this不存在于静态方法中。我敢说你要写一些测试代码来证明我是错的。我曾经考虑过这种方法,但是当你(潜在地)处理很多属性时,这会变得非常混乱。