'命名参数'使用数组

时间:2015-09-08 13:27:56

标签: php arrays oop methods

我的项目中有一些Utilities类,并且正在考虑使用数组来创建"命名参数"。

我的代码允许我链接方法或单独使用它们。例如,我有一个处理字符串的字符串类(有点明显:))

现在,带链接的一组示例方法如下所示:

print Utils\String::Set('my string')->UcFirst()->UcLast()->Get()

虽然没有链接的同样的事情看起来像这样:

$string = Utils\String::UcFirst('my string');
print Utils\String::UcLast($string);

这适用于某些方法,但是诸如"后缀"等方法存在问题。它具有以下参数:$ string,$ suffix。

这会导致链接问题,因为我最终会这样做

Suffix(null, ' New')

哪个看起来不太好。

在这种情况下,使用数组是否可以提供命名参数? 然后我就能用链接来做这个:

Suffix(['suffix' => ' New'])

但是我不确定这对维护项目有多难,以及是否值得放弃非链接方法以便不需要数组。

2 个答案:

答案 0 :(得分:2)

我不会走这条路。数组作为命名参数的替代方法的问题在于,您无法将参数定义为必需或可选,并且无法键入提示,这会使错误更难找到或增加额外验证的要求。

如果您不熟悉它,请考虑使用此库编写代码的方式。任何IDE都可以快速显示方法所需的参数,但如果它只显示数组,我必须仔细查看文档。

我甚至会进一步将静态方法与对象链接方法分开。现在似乎String::Suffix可以使用值参数静态调用,而非静态调用而不使用值参数。除了违反E_STRICT标准之外,它还将两个完全不同的接口混合到一个方法中。

这就是我实现您的API的方式:

namespace Util;

class String // you might want to change the name to "Strings", "string" is a reserved keyword in PHP 7
{
    public static function Suffix($string, $suffix)
    {
        return (new StringWrapper($string))->Suffix($suffix);
    }
}
class StringWrapper
{
    private $value;
    public function __construct($string)
    {
        $this->value = $string;
    }
    public function Suffix($suffix)
    {
        return new static($this->value . $suffix);
    }
    public function __toString()
    {
        return $this->value; 
    }
}

您将看到String中的静态接口只是StringWrapper类中实际实现的一个薄包装器。 StringWrapper是一个不可变的值对象类型,并提供字符串操作的方法。每个方法调用都返回一个包含修改后的值的类的新实例。使用__toString,您最终可以将其转换为标量字符串值(这是您使用Get()方法执行的操作)

Voilà,不再需要命名参数

答案 1 :(得分:1)

您正在做的事情似乎是从函数应用程序的前缀转换为中缀表示法。也就是说,您正在编写f(x1,x2,…,xn)而不是x1->f(x2,…,xn)

您始终可以使用前缀表示法来编写S::UcLast(S::UcFirst("my string"))。简洁性来自use Utils\String as S

要使用->作为中缀表示法的一部分,您需要一个类定义,如下所示(我假设您的实现也是如此)。

class UtilStringProxy
{
  public $string;

  public function __construct($string)
  {
    $this->string = $string;
  }

  public function UcFirst()
  {
    $this->string = S::UcFirst($this->string);
    return $this;
  }

  public function UcLast()
  {
    $this->string = S::UcLast($this->string);
    return $this;
  }

  public function Suffix($suffix)
  {
    $this->string = S::Suffix($this->string, $suffix);
    return $this;
  }

}

第一个论点被剥离了。这就是我们如何将f置于中缀位置(在操作数1和2之间)。然后你可以写:

(new UtilStringProxy("my string"))->UcFirst()->UcLast()->Suffix("New")->string

就我个人而言,我没有看到这个的愿望:

S::Suffix(S::UcLast(S::UcFirst("my string")), "New")

附录

功能组合是另一种查看方式。函数应用程序提供从左到右的读数,而函数组合可以通过翻转参数从左到右或从右到左阅读。

UtilStringProxy的示例基本上是为特定的函数集UcFirst, UcLast, Suffix定义的从左到右的函数组合。你可以概括一下。

class Compose
{
  public $f;

  public function __construct(callable $f)
  {
    $this->f = $f;
  }

  public function lr(callable $g)
  {
    $f = $this->f;
    return new Compose(function ($x) use ($f, $g) {
      return $g($f($x));
    });
  }

  public function rl(callable $g)
  {
    $f = $this->f;
    return new Compose(function ($x) use ($f, $g) {
      return $f($g($x));
    });
  }

  public function call($x)
  {
    $f = $this->f;
    return $f($x);
  }

}

我添加了call方法,因为PHP在其解析器中有一个令人遗憾的弱点,因此您无法编写expr(x)来将expr应用于x任何表达式 - 只有一些。如果您只想返回撰写的函数,请使用->f,如果您想立即应用它,请使用->call(x)

使用此功能,您可以编写从左到右的构图:

(new Compose('strtolower'))->lr('ucfirst')->call("hEllo World")

或从右到左的构图:

(new Compose('ucfirst'))->rl('strtolower')->call("hEllo World")