【问题标题】:Referencing a class programatically in PHP在 PHP 中以编程方式引用类
【发布时间】:2013-05-20 21:31:51
【问题描述】:

我在某个过程中收到一个对象,这个对象需要弄清楚它的配色方案。 例如,我有一个这样存储的配色方案:

class FirstScheme {
    public static $COLORS = array('1' => 'green', '2' => 'red', ...);
}
class SecondScheme {
    public static $COLORS = array('1' => 'red', '2' => 'green', ...);
}

我事先知道所有的配色方案名称;它们只能在代码更改时更改。 但是每个对象要使用的着色方案需要在运行时通过匹配该对象的属性来确定。

我不知道该怎么办。在 python 中,我会定义一个 dict,其中包含颜色方案到名称的映射,如下所示:

d = {'attr_value1': FirstScheme, 'attr_value2': SecondScheme, 'attr_value3': FirstScheme, ...}

然后只需访问“颜色”变量,因为每个类都应该有它。但是在 PHP 中没有办法以这种方式引用一个类,那么正确的方法是什么? 请注意,多个属性可以映射到相同的着色方案。

【问题讨论】:

  • 如果你传递对象而不是类怎么办?静态方法/属性通常被认为是一种不好的做法。在对象的情况下 - 你将有一个单一的类 ColorScheme 并用不同的方案实例化它。
  • 为什么?我不明白当我的配色方案是预先确定的时,为什么我需要一个对象。我不需要实例化它们,我提前知道它们。
  • 它们是预定的事实如何改变静态解决方案很糟糕的事实?创建一个构建器,根据请求创建各种配色方案,并通过接口绑定您的类,而不是通过硬编码的类和属性名称
  • @dragoon Coloring scheme is need to be determined at run-time by matching the attribute of this object你能再解释一下吗?
  • @hek2mgl 当然,我知道所有可能的配色方案,但我将来可能会添加更多。每个传入对象都有一些属性,允许明确映射到其中一个方案。

标签: php class-reference


【解决方案1】:

如果每个类都应该有颜色,定义允许获取颜色的接口:

interface ColorsProvider {
    function getColors();
}
class FirstScheme implements ColorsProvider {
    public static COLORS = array('1' => 'green', '2' => 'red', ...);

    public function getColors() {
        return self::COLORS;
    }
}
class SecondScheme implements ColorsProvider {
    public static COLORS = array('1' => 'red', '2' => 'green', ...);

    public function getColors() {
        return self::COLORS;
    }
}

然后,你有一堆你的参数:

$a = array(
  'attr_value1' => new FirstScheme(),
  'attr_value2' => new SecondScheme(),
);

您可以致电:

$param = 'attr_value1';

if(!isset($a[$param]))
    throw new Exception("undefined param");

if(!($a[$param] instanceof ColorsProvider))
    throw new Exception("Param should point to ColorsProvider");

$a[$param]->getColors();

请注意,它是完全客观的。在 PHP 中有更简单的方法来获得这种效果,但我的解决方案很优雅。


另一点是界面完全分离了颜色的来源。会有来自文件、数据库、xml、硬编码等。


默认实现可能是:

abstract class DefaultColorsProviderImpl implements ColorsProvider             {
    protected static COLORS = array();

    public function getColors() {
        return self::COLORS;
    }
}

class FirstScheme extends DefaultColorsProviderImpl {
    protected static COLORS = array( ... );
}

但仍然允许进行从 e.x. 返回颜色的通用实现。来自文件。

【讨论】:

  • getColors() 实现可能(必须?)移动到父抽象类。并且颜色属性不需要是公共的或静态的
  • 可能是这样,但是这个解决方案(使用接口)允许您从任何来源获取颜色,而不仅仅是硬编码数组(如我所述)。另一种方法是创建从数组返回颜色的默认实现 (ColorsProviderArrayImpl)(这是一种流行的解决方案,正如您所提到的,但仍然基于允许您创建完全不同的实现的接口)。
  • 我仍然看不到代码重复的任何原因(它们仍然实现相同的接口)或将 $COLORS 属性保留为公共和静态(只要您决定使用方法检索它,而不是直接)
  • 考虑:abstract class DefaultColorsProviderImpl implements ColorsProvider { proteted static COLORS = array(); public function getColors() { return self::COLORS; } }class FirstScheme extends DefaultColorsProviderImpl { proteted static COLORS = array( ... ); }这里没有多余的代码。
  • @Athlan 我希望它是静态的原因是多个属性可以(并且将)映射到同一个方案。使用您的示例,我将不得不为不同的属性值多次实例化相同的方案,我认为这不好。
【解决方案2】:

当然可以:

$schemes = [
  'attr_value1' => FirstScheme::$COLORS,
  'attr_value2' => SecondScheme::$COLORS,
  ...
];

甚至在运行时:

$schemes = [
  'attr_value1' => 'FirstScheme',
  'attr_value2' => 'SecondScheme',
  ...
];

然后:

$reflector = new ReflectionClass($schemes['attr_value1']);
$schema = $reflector->getStaticPropertyValue('COLORS');

但这似乎根本无法维护,您希望将此类信息存储在适当的数据层中,而不是将它们硬编码为类的静态字段[这不是他们的目的]。

【讨论】:

    【解决方案3】:

    在他们自己的类中硬编码颜色的另一种方法是:

    class ColorScheme {
    
       protected $colors;
    
       public function __construct(array $colors) {
           $this->colors = $colors;
       }
    
       public function getColors() {
           return $this->colors;
       }
    
    }
    
    $scheme1 = new ColorScheme(array('red', 'blue', 'green'));
    $scheme2 = new ColorScheme(array('yellow', 'pink', 'cyan'));
    

    PHP 中 Python 字典的等价物是关联数组。所以你可以这样做:

    $d = array (
        'values_1' => $scheme1->getColors(),
        'values_2' => $scheme2->getColors()
    );
    

    【讨论】:

    • 我仍然不明白如何在运行时获取映射。
    • $mapping = $scheme1->getColors(); 或者mapping 是什么意思?
    • 好的,我会尝试不同的解释。我有配色方案,就像其中一些一样。他们是事先知道的。他们在运行时我有传入的对象,它拥有一个属性,可以找出我需要应用到它的方案。这就是为什么我把 {'attr_value1': FirstScheme, ...} 放在我的问题中。
    • @dragoon:你确定我们目前没有解决XY-problem 吗?
    • @dragoon:是的,但它没有解释为什么它们应该是静态的。有什么好的理由吗?
    猜你喜欢
    • 1970-01-01
    • 2015-06-19
    • 2011-08-01
    • 2023-04-11
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    相关资源
    最近更新 更多