制作我自己的(非数据库)fetch_object函数 [英] Make my own (non-database) fetch_object function

查看:60
本文介绍了制作我自己的(非数据库)fetch_object函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在php mysql/mysqli/postgre/等中...有fetch_object函数,您可以在其中获取数据行的对象.默认情况下,它将返回stdClass的对象,但是您也可以为构造函数定义class_name和参数数组.

In php mysql / mysqli / postgre / etc... there are fetch_object functions where you can get an object for your row of data. By default it will return an object of stdClass, but you can also define a class_name and an array of params for the constructor.

我想用一组简单的值来做同样的事情.最好在调用构造函数之前,在对象 之前设置属性,这与数据库函数显示的行为相同.但是,这似乎是不可能的.

I would like to do the same thing with a plain set of values. Preferably, setting the properties of the object before calling the constructor, which is the same behaviour the database-functions show. However, this doesn't seem to be possible.

甚至创建具有属性集的对象的唯一方法似乎是反序列化预先构造的字符串.但是该示例仍然会创建一个新对象,然后从未序列化的对象设置该对象的属性,以确保调用了构造函数.但这意味着在设置属性之前先调用构造函数.

The only way to even create an object with properties set seems to be to unserialize a preconstructed string. But that example still creates a new object as well, then sets the properties of that object from the unserialized object to ensure the constructor is called. But this means the constructor is called before the properties are set.

简而言之:我想要以下内容:

In short: I would like the following:

array_fetch_object(array $properties, string $class_name [, array $params ])

在设置属性后调用构造函数.

with the constructor called after the properties are set.

推荐答案

最后,我编写了下面的类,该类使用反序列化伪造的字符串来执行任务.它使用反射来确定属性的访问类型是什么,以及构造函数的名称是什么(如果有).

In the end I wrote the following class which performs the task using unserializing a fabricated string. It uses reflection to determine what the access-type of properties is and what the name of the constructor is (if any).

该类的核心是以下几行:

The heart of the class is the following line:

$object = unserialize('O:'.strlen($class_name).':"'.$class_name.'"'.substr(serialize($properties), 1));

序列化属性数组,并将序列化的序列重命名为所需的class_name.

which serializes the property-array and renames the serialized to the desired class_name.

class ObjectFactory {

    private $properties;
    private $constructors;

    public function __construct() {
        $this->properties   = array();
        $this->constructors = array();
    }

    private function setClass($class_name) {

        $class = new ReflectionClass($class_name);
        $this->properties[$class_name] = array();

        foreach($class->getProperties() as $property) {

            $name     = $property->getName();
            $modifier = $property->getModifiers();

            if($modifier & ReflectionProperty::IS_STATIC) {
                continue;
            } else if($modifier & ReflectionProperty::IS_PUBLIC) {
                $this->properties[$class_name][$name] = $name;
            } else if($modifier & ReflectionProperty::IS_PROTECTED) {
                $this->properties[$class_name][$name] = "\0*\0".$name; // prefix * with \0's unserializes to protected property
            } else if($modifier & ReflectionProperty::IS_PRIVATE) {
                $this->properties[$class_name][$name] = "\0".$class_name."\0".$name; // prefix class_name with \0's unserializes to private property
            }
        }

        if($constructor = $class->getConstructor()) {
            $this->constructors[$class_name] = $constructor->getName();
        }
    }

    private function hasClassSet($class_name) {

        return array_key_exists($class_name, $this->properties);
    }

    private function hasClassProperty($class_name, $property_name) {

        if(!$this->hasClassSet($class_name))
            $this->setClass($class_name);

        return array_key_exists($property_name, $this->properties[$class_name]);
    }

    private function getClassProperty($class_name, $property_name) {

        if(!$this->hasClassProperty($class_name, $property_name))
            return false;

        return $this->properties[$class_name][$property_name];
    }

    private function hasClassConstructor($class_name) {

        if(!$this->hasClassSet($class_name))
            $this->setClass($class_name);

        return $this->constructors[$class_name] !== false;
    }

    private function getClassConstructor($class_name) {

        if(!$this->hasClassConstructor($class_name))
            return false;

        return $this->constructors[$class_name];
    }

    public function fetch_object(array $assoc, $class_name = 'stdClass', array $params = array()) {

        $properties = array();

        foreach($assoc as $key => $value) {
            if($property = $this->getClassProperty($class_name, $key)) {
                $properties[$property] = $value;
            }
        }

        $object = unserialize('O:'.strlen($class_name).':"'.$class_name.'"'.substr(serialize($properties), 1));

        if($constructor = $this->getClassConstructor($class_name)) {
            call_user_func_array(array($object, $constructor), $params);
        }

        return $object;
    }
}

这篇关于制作我自己的(非数据库)fetch_object函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆