1

我的构造函数中有很多这样的代码:-

function __construct($params) {

    $this->property = isset($params['property']) ? $params['property'] : default_val;

}

一些默认值取自其他属性,这就是我在构造函数中这样做的原因。但我想它可以在 setter 中完成。

这种方法的优缺点是什么,还有更好的方法吗?

编辑:我有一些依赖关系,如果数组中未提供$params属性,则该值取自另一个属性,但是其他属性可能是可选的并且具有默认值,因此初始化属性的顺序很重要。

这意味着如果我使用 getter 和 setter,那么调用它们的顺序并不明显,因为依赖项在 getter 中被抽象出来,而不是在构造函数中......

4

3 回答 3

1

我建议您编写适当的 getter/setter 函数,它为您断言正确的数据类型和验证(并包含您提到的默认值逻辑)。这些应该在您的构造函数中使用。当设置多个相互依赖的字段时,为这些复杂数据设置一个单独的设置器似乎很好。无论如何,他们以哪种方式依赖?

例如:

// META-Config
protected $static_default_values = array(
  "price" => 0.0,
  "title" => "foobar"
  // and so on
);

protected $fallback_getter = array(
  "price" => "getfallback_price"
);


// Class Logic
public function __construct($params){
  $this->set_properties($params);
}

public set_properties($properties){
  // determines the sequence of the setter-calls
  $high_prio_fields = array("price", "title", "unimportant_field");

  foreach($high_prio_fields as $field){
    $this->generic_set($field, $properties[$field]);
    // important: unset fields in properties-param to avoid multiple calls
    unset($properties[$field]);
  }

  foreach($properties as $field => $value){
    $this->generic_set($field, $value);
  }
}

// this could also be defined within the magic-setter,
// but be aware, that magic-functions can't be resolved by your IDE completely
// for code-completion!
private function generic_set($field, $value){
  // check if setter exists for given field-key
   $setter_func = "set_".$v;
   if(method_exists($this, $setter_func){
     call_user_func_array(array($this, $setter_func), array($v));
   }
   // else => just discard  :)        
}

// same comment as generic-set
private function generic_get($field){
  // check if value is present in properties array
  if(isset($this->properties[$field]){
    return $this->properties[$field];
  }

  // check if fallback_getter is present
  if(isset($this->fallback_getter[$field]){
    return  call_user_func_array(array($this, $this->fallback_getter[$field]));
  }

  // check for default-value in meta-config
  if(isset($this->static_default_values[$field]){
    return $this->static_default_values[$field];
  }

  // else => fail (throw exception or return NULL)
  return null;
}


public function get_price(){
  // custom getter, which ovverrides generic get (if you want to)
  // custom code...
  return $this->generic_get("price");
}

private function getfallback_price(){
  return $this->properties["other_value"] * $this->properties["and_another_value"];
}

public function set_price($price){
  $price = (float) $price; // convert to correct data-type
  if($price >= 0.0){
    $this->properties["price"] = $price;
  }
  // else discard setting-func, because given parameter seems to be invalid
  // optional: throw exception or return FALSE on fail (so you can handle this on your own later)
}

更新您的编辑: 修改后的源代码应该可以解决您的所有需求(setter-funcs 的顺序,get-value 的不同解析)。

于 2012-04-07T10:21:52.807 回答
0

创建“全球可用”功能array_get

public static function array_get($array, $property, $default_value = null) {
    return isset($array[$property]) ? $array[$property] : $default_value;
}
于 2012-04-07T10:17:36.267 回答
0

当有很多默认选项并且您需要能够覆盖它们时 - 正如您之前在 jQuery 中看到的那样.extend()- 我喜欢使用这种简单快捷的方法:

class Foo {
    private $options;

    public function __construct($override = array()) {
        $defaults = array(
           'param1' => 'foo', 
           'param2' => ..., 
           'paramN' => 'someOtherDefaultValue');
        $this->options= array_replace_recursive($defaults, $override);
    }
}     

特别是对于开始类来说,这是一种非常简单和灵活的方式,但正如已经提到的,如果该代码将被大量使用,那么使用 getter 和 setter 对这些选项进行更多控制可能不是一个坏主意,尤其是如果您需要在获取或设置其中一些选项时采取措施,例如在我正确理解您的问题的情况下依赖关系。

另请注意,您不必自己实现 getter 和 setter,在 PHP 中您可以使用 __get 和 __set 魔术方法。

它遵循一些无用的代码,希望能提供一些想法:

[...inside Foo...]
public function __set($key, $value){
    switch(true){
        //option exists in this class
        case isset($this->options[$key]):
           //below check if $value is callable
           //and use those functions as "setter" handlers
           //they could resolve dependencies for example 
           $this->options[$key] = is_callable($value) ? $value($key) : $value;  
        break;
        //Adds a virtual setter to Foo. This so called 'magic' __set method is also called if the property doesn't exist in the class, so you can add arbitrary things.
        case $key === 'someVirtualSetterProp': Xyzzy::Noop($value); break;
        default: 
           try{ parent::__set($key, $value); } catch(Exception $e){ /* Oops, fix it! */ }
    }
}

请注意,在上面的示例中,我采用了不同的方法,这样混合它们通常没有意义。我这样做只是为了说明一些想法,希望您能够更好地决定什么更适合您的需求。

于 2012-04-07T11:11:24.120 回答