【问题标题】:PHP Discussion - pass parameters as array or a "Configuration" ClassPHP 讨论 - 将参数作为数组或“配置”类传递
【发布时间】:2019-01-27 00:36:00
【问题描述】:

首先,如果这个问题不属于这里(并且有更好的地方),请告诉我。

其次,我问的是关于“代码质量”而不是“性能”的问题。

第三,这实际上与 PHP 无关,但由于每个语言都有其“良好实践”,我更喜欢指定它。

最后,如果有类似的问题,抱歉,我没找到。

现在的问题:

将方法参数作为数组还是 "Configuration" 类更好?

例如,我正在使用 Doctrine,在我的 Reporsitory 中,我经常有一种方法接受“标准”,另一种方法 prepareCriteria 使用 $criteria 数组来构建 QueryBuilder

在这些情况下,我使用数组的次数越多,我就越想知道是否有一些 CriteriaBuilder(或 CriteriaConfiguration 或其他)来完全控制传递的参数的类型,而不是依赖于数组的简单字符串键。

您对此有何看法?

ps:我真的不知道什么样的标签可以适合这类问题。 我添加了doctrine 作为示例,但如果您有更精确的标签可以使用,请告诉我。

【问题讨论】:

  • 但实际上你的“配置”类只是一个奇特的数组。我尽量远离多层次的抽象,你继续前进,你将有 10 个类来处理一个数组。 CriteriaBuilderMessageHookHandler 会在某处:) 保持简单
  • 您的问题确实不属于这里,因为它主要是基于意见的。什么是更好的?谁来决定?谁能用事实而不是个人观点来回答你的问题?最后,您的个人意见将是没有任何事实支持的“最佳”答案。这就是为什么这是一个离题的问题。
  • 我不知道这个 Q 的正确位置可能在哪里,但是,这里“主要基于意见”的问题将被投票关闭。 PHP是一种痛苦。通常,在创建关联数组时,类会更好地防止由于拼写错误而导致的错误。但是,这在大型项目中是很多开销。除了将二进制标志常量用于一组布尔选项之外,还没有真正好的替代方案。
  • PHP 中的类声明不会阻止实例隐式声明更多属性,即使是从外部。使用魔术方法__set 既昂贵又烦人。没有像 C# new MyClass(){prop1="foo", prop2="bar"} 这样的简单初始化程序,您必须编写一个构造函数,它不提供像 Perl 那样的调用命名属性,而只提供位置参数 - 可读性不强。再说一次,PHP 很痛苦。
  • 要获得更多关于主题的信息,您可能需要编辑您的问题并提出以下问题:“传递一些复杂配置设置的可靠方法是什么?”您可以展示两个传递数组和对象的示例。您应该继续使用 PHP 作为语言,因为取决于语言规范,不同的做法适用。

标签: php doctrine doctrine-odm


【解决方案1】:

PHP 中的最佳实践可能是使用详细的关联数组和字符串 assertions,当断言在生产系统上被禁用时,或者从 PHP7 开始,甚至是零成本的expections,开销很小。编写代码时很烦人,但在以后的代码审查中可读,并且在开发时测试代码时也会发现错误。

只是举个例子:

php.ini

zend.assertions  = 1
assert.warning   = 1
assert.exception = 1
assert.bail      = 1

PHP

function foobar(array $config)
{    
  assert
  (
    (function($keys_allowed, $keys_expected)use($config)
    {
      // do not stop execution until all issues are output
      $opt_expt = assert_options(ASSERT_EXCEPTION, 0);
      $opt_bail = assert_options(ASSERT_BAIL     , 0);

      $ok = 1;

      $ok &= assert( empty( $diff = array_diff_key(array_fill_keys($keys_expected, 1), $config) ),
                     new AssertionError('Missing mandatory keys: (' . join(', ', array_keys($diff)) . ')'));

      $ok &= assert( empty( $diff = array_diff_key($config, $keys_allowed) ),
                     new AssertionError('Disallowed keys: (' . join(', ', array_keys($diff)) . ')'));

      $ok &= assert( empty( $diff = array_filter
                                    ( $config,
                                      function($v, $k)use($keys_allowed)
                                      {
                                        return isset($keys_allowed[$k]) && $keys_allowed[$k] !== gettype($v);
                                      },
                                      ARRAY_FILTER_USE_BOTH)
                                    ),
                     new AssertionError('Type error on items: (' . join(', ', array_keys($diff)) . ')'));

      //restore configured behaviour    
      assert_options(ASSERT_EXCEPTION, $opt_expt);
      assert_options(ASSERT_BAIL     , $opt_bail);
      return $ok;
    })
    (
      [ 'foo' => 'string', 'bar' => 'integer', 'baz' => 'boolean' ],   [ 'baz' ]
    )
    , new AssertionError('Arguments assertion in function `' . __FUNCTION__ . '` failed.')
  );


  // foobar function stuff
  echo 'Ok!', PHP_EOL;
}

// test
foobar(['foo' => '1',              'baz' => true                     ] );  // Ok!
foobar([              'bar' => 1 , 'baz' => true                     ] );  // Ok!


foobar(['foo' => 1  ,              'baz' => true                     ] );  // Warning: type ; Fatal error
foobar(['foo' => '1', 'bar' => 1                                     ] );  // Warning: missing ; Fatal error
foobar(['foo' => 1  , 'bar' => '1'               , 'forbidden' => 'x'] );  // Warnings: missing, disallowed, type ; Fatal error

外部断言抛出一个致命错误,停止执行,而内部断言抛出非破坏性警告。

您可以轻松地将匿名函数转换为将使用的变量作为附加参数的命名函数。

【讨论】:

    猜你喜欢
    • 2012-03-15
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 2018-02-01
    • 1970-01-01
    • 2011-08-12
    • 2016-09-26
    相关资源
    最近更新 更多