这个功能有太多参数吗?

jus*_*joe 19 php parameters coding-style function

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

function user_registration($user_name, $user_email, $user_pass, $address, 
                           $city, $postalcode, $country, $phone, $mobilephone)
Run Code Online (Sandbox Code Playgroud)

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

Flo*_*anH 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);
Run Code Online (Sandbox Code Playgroud)

  • 我不认为用户对象应该有责任自己注册.因此我投了这个解决方案. (5认同)
  • 多么无聊啊 (2认同)

Pas*_*TIN 13

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

您的功能可以这样定义:

function user_registration(array $data) {
    // work with $data['name']
    // and $data['email']
    // ...
}
Run Code Online (Sandbox Code Playgroud)

你会这样称呼它:

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


好东西是:

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

不是那么糟糕的事情是:

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


CRe*_*lts 9

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

"如果它没有破坏就不要修理它!"

  • 我要么保留参数并在函数内运行检查,要么按照FlorianH的建议创建用户类以获得更多的OO设计.传递数组真的不清楚,并且容易传递错误的参数名称(数组索引). (3认同)

Gor*_*don 6

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

User Data:    $user_name, $user_pass
Address Data: $address, $city, $postalcode, $country
Contact Data: $user_email, $phone, $mobilephone
Run Code Online (Sandbox Code Playgroud)

因此,您可以应用Introduce Parameter Object:

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

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

function user_registration(User $user, Address $address, Contact $contact)
Run Code Online (Sandbox Code Playgroud)

查看该参数列表应该会让您注意到Address和Contact可能首先属于User,因此您可以考虑将函数签名更改为just

function user_registration(User $user)
Run Code Online (Sandbox Code Playgroud)

然后像这样调用它:

$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);
Run Code Online (Sandbox Code Playgroud)

我们可能也会将用户名和密码设置为Credentials对象,然后就可以了

user_registration(new User($credentials, $address, $contact));
Run Code Online (Sandbox Code Playgroud)

通过要求ctor中的数据,我们确保新注册的用户确实拥有所有这些信息.我们可以争论是否需要Address和Contact来注册用户,所以Setter注入可能在这里足够好:

$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);
Run Code Online (Sandbox Code Playgroud)

但是,user_registration由于全球范围内的单独功能是错误的.根据GRASP的信息专家原则,方法应该在具有最多信息的对象上履行职责.这提高了Cohesion并减少了耦合.换一种说法:

$user = new User($credentials);
$user->setAddress($address);
$user->setContact($contact);
$user->register();
Run Code Online (Sandbox Code Playgroud)

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

$user = new User;
$user->setAddress($address);
$user->setContact($contact);
$user->register($credentials);
Run Code Online (Sandbox Code Playgroud)

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

最后,您可能希望添加Simple Factory或Builder模式来封装User的创建,以简化各种实例的聚合.或者您可能想要引入Repository模式并将方法移动到register()那里.但这超出了这个问题的范围.