这个功能有太多参数吗?

时间:2010-04-05 13:51:34

标签: php function parameters coding-style

最后,我得到了这个功能。我不知道这是否正常。

function user_registration($user_name, $user_email, $user_pass, $address, 
                           $city, $postalcode, $country, $phone, $mobilephone)

我如何以及为何可以改善这一点?

10 个答案:

答案 0 :(得分:23)

你可以传递一个包含所有变量的数组,或者只是创建一个“User”类并通过setter添加所有属性,并使用专用方法进行验证:

class User {

  public function setName($name) {
    $this->name = $name;
  }

  [...]

  public function register() {

    //Validate input
    if (empty($this->name))
      $this->errors[] = "ERROR, Username must not be emtpy";

    //Add the user to the database
    //Your SQL query
    return empty($this->errors);
  }

}

$user = new User();
$user->setName("Peter");
$success = $user->register();

if (!$success)
  echo "ERRORS OCCURED: ".print_r($user->errors, true);

答案 1 :(得分:13)

解决方案是只有一个参数,可以包含几个数据 - 比如数组。

您的功能可以这样定义:

function user_registration(array $data) {
    // work with $data['name']
    // and $data['email']
    // ...
}

你会这样称呼它:

user_registration(array(
    'name' => 'blah',
    'email' => 'test@example.com', 
    'pass' => '123456',
    // and so on
));


好东西是:

  • 您可以轻松添加/删除“参数”
  • “参数”可以按您想要的任何顺序传递

不是那么糟糕的事情:

  • 在IDE中输入时没有提示
  • 没有文档(如phpDoc)

答案 2 :(得分:9)

我个人认为它没有太多参数。通过查看函数定义,您可以清楚地了解所需的输入,如果使用数组调用则不会那么明显。

“如果它不能解决它!”

答案 3 :(得分:5)

当您查看您的参数名称时,您不能不注意到它们可以分为三个不同的组:

User Data:    $user_name, $user_pass
Address Data: $address, $city, $postalcode, $country
Contact Data: $user_email, $phone, $mobilephone

因此,您可以应用Introduce Parameter Object

  

通常,您会看到一组特定的参数,这些参数通常会一起传递。有几种方法可以在一个类或几个类中使用该组。这样的一组类是数据块,可以用携带所有这些数据的对象替换。将这些参数转换为对象只是为了将数据分组在一起是值得的。这种重构很有用,因为它减小了参数列表的大小,并且很难理解长参数列表。新对象上定义的访问器也使代码更加一致,这再次使其更容易理解和修改。

如果你不想做OOP,你也可以将参数分组到数组中,但是你将失去所有类型的好处。我只是假设你不介意使用对象。因此,在应用重构后,您将最终得到

function user_registration(User $user, Address $address, Contact $contact)

查看该参数列表会让您注意到地址和联系人可能首先属于用户,因此您可以考虑将功能签名更改为

function user_registration(User $user)

然后像这样调用它:

$user = new User('johndoe', 'secretsauce');
$user->setAddress(new Address('Doe Street', 'Doe Town', 12345, 'Neverland'));
$user->setContact('jdoe@example.com', '+123 12345', '+123 54321');
user_registration($user);

我们可能也会在Credentials对象中创建用户名和密码,然后执行

user_registration(new User($credentials, $address, $contact));

通过要求ctor中的数据,我们确保新注册的用户确实拥有所有这些信息。我们可以争论是否需要地址和联系人来注册用户,所以Setter injection在这里可能还不错:

$user = new User(new Credentials('johndoe', 'secretsauce'));
$user->setAddress(new Address('Doe Street', 'Doe Town', 12345, 'Neverland'));
$user->setContact(new Contact('jdoe@example.com', '+123 12345', '+123 54321'));
user_registration($user);

但是,user_registration作为全局范围内的单独函数是错误的。通过GRASP's Information Expert principle,方法应该放在具有最多信息来履行职责的对象上。这会改善Cohesion并减少Coupling。换句话说:

$user = new User($credentials);
$user->setAddress($address);
$user->setContact($contact);
$user->register();

User类的一个问题是它包含密码。只需要密码就可以根据身份验证服务对用户进行身份验证。我们可以争论用户名,但密码绝对不应该是User对象的一部分。所以你应该做类似

的事情
$user = new User;
$user->setAddress($address);
$user->setContact($contact);
$user->register($credentials);

并且在调用register()时,它将仅使用凭据将新用户的插入委派给用户存储。但它不会将它们保留在实际的用户实例中。

最后,您可能希望添加Simple Factory or Builder pattern来封装用户的创建,以简化各种实例的aggregation。或者您可能想在那里引入Repository patternmove the register() method。但这超出了这个问题的范围。

答案 4 :(得分:4)

作为一般的经验法则(不是一个坚定的规则),任何时候你都要问“这个函数有太多的参数吗?” - 答案是。你的直觉告诉你一些你的大脑尚未能解决的问题。

在这种特殊情况下,我想到的第一件事就是首先检查你的用户信誉(用户名是否已经存在?是否足够复杂),你的用户详细信息应该单独添加,可能使用对象或数组。

答案 5 :(得分:3)

一种方法是将数组作为参数传递给此函数,并将所有信息放在该数组中:

function user_registration(array $user_info)
{
   // process $user_info;
}

答案 6 :(得分:2)

我制作像

这样的数组
$fields = array('field1', 'field2');
function register (array $values, array $keys)
{
    $data = array();
    foreach ($keys as $one)
    {
        if (isset($values[$one])) $data[$one] = $values[$one];
    }
    // or you can use array functions like array_flip and after - array intersect
}

答案 7 :(得分:2)

没有任何参数的函数(方法)是最好的。使用一个参数的功能优于具有2个参数的功能。具有2个参数的功能优于具有3个参数的功能,依此类推。

答案 8 :(得分:2)

@Florianh为您的代码提供了完美的解决方案。有了这个评论,我想从系统设计的角度详细阐述“为什么”部分。

从面向对象的角度来看,其他对象应该能够操纵属性。这就是为什么属性永远不应该被定义为“公共”的原因。它们应该是“私人的”,例如:

private var $name;

原因是当其他对象操纵此变量时,对象的正确工作处于危险之中。另一方面,方法可以公开定义:

public function register() 

因此,属性的操纵将通过适当的方法进行。可以使用方法来评估属性上的操作的正确性。

可以发生两种操作:读取属性的当前值,方法是使用获取方法保存新值使用设置方法进行属性。

一个好的做法是为每个类属性实现一个get方法。每个可以修改的属性也应该有一个合适的set方法。

有时最好不要实现get / set方法(例如:showData())。这是因为在特定类中使用getter和setter可能会导致性能降低。但是,这意味着在更改或实现类时,在尝试保存错误信息时必须小心,因此会使类的完整性处于危险之中。

现在,请考虑您决定只使用一个电话号码而不是电话号码和手机号码。当移动电话号码被弃用时,您的主程序仍然保持不变。您所要做的就是更改/删除一种方法。使用getter和setter的优势在于增强了适应性可维护性

答案 9 :(得分:-6)

我会这样做

fields=explode(",","name,surname,lastname,street,city,region,zip,country");
user_registration($fields);

因为我确定这些变量来自$ _POST