这可能是一个普遍的问题,我读过的99%的解决方案只是使用isset
来保证安全和冗长。但是,我仍然认为它并不那么优雅,也有点重复。
为了更好地理解我的问题,这是我的代码的一般模式:
public static function buildObject(array $userProperties) {
// Here, I'm building a user from an associative array.
// If the developer passes in an array with missing name or address,
// this will generate an undefined index notice!
$user = new User();
$user->setName($userProperties['name']);
$user->setAddress($userProperties['address']);
return $user;
}
到目前为止我已尝试过:
在所有设置的调用中添加isset()
检查。对于这个例子,这可能不是一个坏主意,但是我有一些具有很多属性的巨大类,它看起来和感觉非常重复。
通过循环遍历属性并将它们设置为null(如果它们不存在于数组中)来使阵列安全。这在代码中看起来并不好,但感觉就像是一种解决方法。
使用null coalesce operator ?? null
。这也感觉重复,而且不那么可读。
我更喜欢一个简单的解决方案,它不会添加太多逻辑,但会显得优雅。我知道在这里进行验证更可取,但在处理可选字段时我会遇到同样的问题。
答案 0 :(得分:2)
优雅没有客观指标。一个开发人员可能会发现优雅的其他人会发现冗长和重复。无论什么被认为是 best 这样的事情总是完全主观的。
话虽如此,如果你发现自己做了一些不必要的重复和冗长的事情,那通常是一种可以改进的气味。
根据您的使用方向,您的用例可能的解决方案会有很大差异。您可以创建一个实现ArrayAccess
的参数对象,这样消费者仍然可以将参数视为数组,但您可以在方法中更简洁地使用它。
或者您可以使用流畅的界面创建构建器对象,以便创建用户根本不需要数组:
$user = UserBuilder::start()
->setName('Foo')
->setLastName('Bar')
->build();
但这一切都取决于您的实施细节,您愿意为此相对方便而进行的额外工作,以及您想要解决的具体内容。
将关联数组作为参数传递时,一种非常常见且非常简单的模式,并且您希望可以访问某些保证的键;是使用array_merge()
。
E.g:
function foo(array $arguments) {
$arguments = array_merge( [
'name' => null,
'lastName' => null,
'role' => ROLE_USER
],
$arguments);
}
没有多少魔法会为没有收到一个的User
对象命名,但这样至少设置了数组键,你可以用它来设置其他默认值和他们一起工作。
最后,你必须决定什么对你有用,你认为优雅是什么,以及在你的项目中哪种实施真的值得。