【问题标题】:Creating Object instance from Posted data - PHP从发布的数据创建对象实例 - PHP
【发布时间】:2009-09-16 11:50:43
【问题描述】:

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

例如,如果我有一个具有属性 Colour、Model、Make、Year 和方法 Save 的 Car 类,该方法将插入或更新记录。

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

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

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

感谢任何关于最佳实践的建议

干杯 斯图尔特

【问题讨论】:

    标签: php oop


    【解决方案1】:

    你可以使用一点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]);
        }
    }
    

    你可以在一个基类中实现这个方法,并让你的所有对象都继承自它,这样你就可以在每个对象中拥有这个功能,而无需在任何类中重复自己。

    【讨论】:

      【解决方案2】:

      如果属性是公开的:

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

      如果他们需要二传手:

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

      【讨论】:

        【解决方案3】:

        我将实现魔术函数__set_state(),因为它正是针对这个用例而设计的。将实现放入该方法有多种好处:

        1. 定义得很好,这个函数的作用(它在 PHP 文档中定义,与您自己的源代码形成对比)
        2. 您可以在函数内访问私有成员
        3. 使用var_export() 转储的对象将使用此函数自动重建。

        编辑根据 cmets 的要求:

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

        编辑满足来自 cmets 的另一个请求:

        除非您使用 php 5.3,否则您无法知道在哪个类上调用了静态方法,其中引入了所需的功能 (late static binding)。您可以通过分析当前堆栈(使用debug_backtrace())来模拟get_called_class()。如果您有一个有效的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;
            }
        }
        

        【讨论】:

        • 我认为这种方法的实现将(足够接近)与上述 Chaos 的建议相同吗?
        • 是的,实现是一样的。扩展答案来解释我为什么建议这种方法。
        • 您确定可以访问私人会员吗? __set_state 应该是静态函数, $this 没有在其中定义,而是创建一个新的对象实例,然后为其分配变量。那么,请解释一下如何从函数中访问私有变量?
        • private 成员可以从定义它们的类中的任何地方访问,如果需要,您可以编写一些测试代码。唯一不能访问的私有成员是继承的。
        • 不能从你的静态 __set_state 函数访问私有成员,因为 $this 在静态方法中不存在。我敢让你写一些测试代码来证明我错了。
        【解决方案4】:

        嗯,你可以一步将 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】:

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

          【讨论】:

            【解决方案6】:

            创建一个包含所有属性的构造函数

            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
            }
            

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

            【讨论】:

            • 我已经考虑过这种方法,但是当您(可能)处理大量属性时,这会变得非常混乱。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-12-15
            • 2015-02-22
            • 1970-01-01
            • 2023-02-08
            • 2011-08-06
            • 2021-07-22
            • 1970-01-01
            相关资源
            最近更新 更多