代码之家  ›  专栏  ›  技术社区  ›  Stuart

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

  •  7
  • Stuart  · 技术社区  · 17 年前

    从窗体传入的值创建和填充对象的最佳方法是什么?

    例如,如果我有一辆具有属性“颜色”、“型号”、“品牌”、“年份”和“方法保存”的类车,它将插入或更新记录。

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

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

    最好对每个方法都调用set方法吗?或者将数组传递给一个方法(或构造函数),然后该方法调用set方法?或者其他方式?

    任何关于最佳实践的建议都会受到赞赏。

    干杯 斯图尔特

    6 回复  |  直到 17 年前
        1
  •  2
  •   soulmerge    17 年前

    我会实现魔法功能 __set_state() ,因为它正是针对这个用例的。将实现放入该方法有多种好处:

    1. 它定义得很好,这个函数的作用是什么(它是在php文档中定义的,与您自己的源代码不同)
    2. 您可以在函数内访问私有成员
    3. 倾倒对象 var_export() 将使用此功能自动重建。

    编辑 根据评论要求:

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

    编辑 完成评论中的另一个请求:

    除非您使用的是php 5.3(其中需要的特性),否则您无法知道在哪个类上调用了静态方法。( late static binding )介绍。你能做什么来模仿 get_called_class() 通过分析当前堆栈(使用 debug_backtrace() )如果你有工作 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;
        }
    }
    
        2
  •  6
  •   Davide Gualano    17 年前

    你可以用一点 Reflection 魔术:

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

    您可以在基类中实现此方法,并使所有的对象都继承自该方法,因此您在每个对象中都具有此功能,而不必在任何类中重复自己。

        3
  •  4
  •   chaos    17 年前

    如果属性是公共的:

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

    如果需要设置器:

    foreach($_POST as $key => $value) {
        $set = 'Set' . $key;
        $obj->$set($value);
    }
    
        4
  •  1
  •   Rik Heywood    17 年前

    好吧,你可以在一个步骤中将post数组转换成一个对象…

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

    编辑: 添加了指向php文档的链接。 http://uk.php.net/manual/en/language.types.object.php

    如果您想对自己的对象类执行此操作,那么采用post数组并设置类的某种构造函数或函数将是正确的。

    class MyCar {
      public function __construct($postdata) 
      {
        $this->Colour = $postdata['Colour'];
        // etc
      }
    };
    
    $car = new MyCar($_POST);
    
        5
  •  1
  •   Ates Goral    17 年前

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

        6
  •  0
  •   knittl    17 年前

    创建一个将获取所有属性的构造函数

    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
    }
    

    请务必预先清理/验证您的输入!(不能经常强调这一点)