0

我今天一直在玩 Zend Hydrator 类,刚刚找到了用于即时转换输入键的命名策略。但是,当将 MapNamingStrategy 与 ObjectProperty 水合器一起使用时,如果输入数组包含它们,它似乎会添加最初不存在于对象中的属性。

有什么方法可以限制它添加新属性并且只填充/水合输入对象中的现有属性?

4

1 回答 1

0

对此仍然没有回应 - 我最终做的是使用两种情况之一,但它仍然不理想。第一个是自己使用类反射来获取可访问的键列表或搜索相同的标准名称访问器。(当然,这不会找到魔术方法访问器)第二个是预定义一个映射,它不仅包括不匹配的 key->property 映射,还包括所有一对一(匹配的)key->属性映射然后在使用映射的键/值对运行水合之前使用 PHP 的数组函数过滤输入。但是这种方式违背了使用水合作用的目的,因为到那时,我还不如使用 foreach 循环。它消除了使用抽象目的地的任何能力,因为您必须知道所有潜在的输入/输出键->

我最终自己实现了第一个方法(同样,它不一定会处理魔术方法访问器),它寻找公共属性和/或公共访问器适合标准驼峰式 setPropertyName()/getPropertyName() 访问器方法:

<?php
/**
 * simple object hydrator using class reflection to find publicly accessible properties and/or methods
 *
 * Created by PhpStorm.
 * User: scottw
 * Date: 12/12/16
 * Time: 12:06 PM
 */

namespace Finao\Util;

class SimpleHydrator
{
    /**
     * whether to reset the keyMap following each hydration to clear the hydrator for other data/object pairs
     *
     * @var bool $resetMap
     */
    private static $resetMap = true;

    /**
     * associative array of key mappings between incoming data and object property names/accessors
     * @var array $keyMap
     */
    private static $keyMap = array();
    public static function setKeyMap($map) {
        if(self::is_assoc($map))
            static::$keyMap = $map;
    }
    public static function populateObject(&$targetObject, $dataArray)
    {
        if (self::is_assoc($dataArray) && is_object($targetObject)) {
            // step through array elements and see if there are matching properties or methods
            try {
                foreach ($dataArray as $k => $v) {
                    $key = $k;
                    if(self::is_assoc(static::$keyMap) && array_key_exists($k))
                        $key = static::$keyMap[$k];
                    // if original value contains an object, try populating it if the associated value is also array
                    $origVal = self::getObjectPropertyValue($targetObject, $key);
                    if (is_object($origVal) && self::is_assoc($v)) {
                        self::populateObject($origVal, $v);
                        $v = $origVal;
                    }

                    $accessor = 'set' . ucfirst($key);
                    if (in_array($key, self::getObjectPublicProperties($targetObject)))
                        $targetObject->$key = $v;
                    elseif (in_array($accessor, self::getObjectPublicMethods($targetObject)))
                        $targetObject->$accessor($v);

                }
            } catch (\Exception $d) {
                // do something with failures
            }

            if(static::$resetMap) static::$keyMap = array();
        }

        return $targetObject;
    }

    public static function getObjectPropertyValue($object, $property)
    {
        $objectReflection = new \ReflectionClass($object);
        if ($objectReflection->hasProperty($property) && $objectReflection->getProperty($property)->isPublic())
            return $object->$property;
        else {
            $accessor = 'get' . ucfirst($property);
            if ($objectReflection->hasProperty($accessor) && $objectReflection->getMethod($accessor)->isPublic())
                return $object->$accessor();
        }
    }

    public static function getObjectPublicProperties($object)
    {
        if (is_object($object)) {
            $publicProperties = array();
            $objectReflection = new \ReflectionClass($object);
            foreach ($objectReflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $p)
                array_push($publicProperties, $p->name);
            return $publicProperties;
        }
    }

    public static function getObjectPublicMethods($object)
    {
        if (is_object($object)) {
            $publicMethods = array();
            $objectReflection = new \ReflectionClass($object);
            foreach ($objectReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $p)
                array_push($publicMethods, $p->name);
            return $publicMethods;
        }
    }

    /**
     * Determine if a variable is an associative array.
     *
     * @param  mixed   Input variable
     * @return boolean If the input variable is an associative array.
     * @see http://us2.php.net/manual/en/function.is-array.php
     */
    public static function is_assoc($array) {
        return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
    }
}

我最终为它添加了一个简单的键映射功能。(请注意,这尚未经过严格测试,顾名思义,这只是一个简单的解决方案。)

于 2016-12-29T16:07:33.907 回答