PHP一种友好的函数传参模式设计,有需要的朋友可以参考下。
当一个类的构造函数函数中,需要传入的参数较多时,程序员在编码时由于传参的顺序和写法难记忆,容易出现编译错误,或者出现值传给错误参数(弱类型语言)的情况.
友好的功能设计
程序员在实例化一个class时,传入的参数应该满足以下 友好性目标:
1. 能够只传入部分参数
2. 能够不按顺序传入参数
3. 能够不区分参数的大小写
4. 能够及时准确的提示传参时产生的错误
改进流程
例1-在成员变量中赋默认值
请看以下代码,函数的默认值在成员变量中赋予,这样在只传入部分参数时,系统会产生notice,即不满足"友好性目标"中的第一条.
- class FileUpload
- {
- private $filepath; //指定文件保存的路径
- private $allowtype = array("gif", "jpg", "jpeg", "png"); //允许的类型
- private $maxsize = 1000000; //允许上传的文件大小 1M
- private $israndname = true; //是否重命名文件
- function __construct($filepath, $allowtype, $maxsize, $israndname)
- {
- $this->filepath = $filepath;
- $this->allowtype = $allowtype;
- $this->maxsize = $maxsize;
- $this->israndname = $israndname;
- var_dump($this);
- }
- }
例2-在构造函数中赋默认值
这一次,为了消除上例的notice,实现可以传入任意数量的参数,没有传入的参数使用默认值,将程序改为:在构造函数中设定默认值.
又一个问题出现:当程序员传入参数为(“/upload”,array(“jpg”,”gif”),false)时,即程序员忘记传入了maxsize参数,这时系统会错误的将false赋值给maxsize而不是israndname,系统没有任何错误输出,为后续工作留下隐患!
- class FileUpload
- {
- private $filepath;
- private $allowtype;
- private $maxsize;
- private $israndname;
- function __construct(
- $filepath = "/upload",
- $allowtype = array("gif", "jpg", "jpeg", "png"),
- $maxsize = 1000000,
- $israndname = true)
- {
- $this->filepath = $filepath;
- $this->allowtype = $allowtype;
- $this->maxsize = $maxsize;
- $this->israndname = $israndname;
- var_dump($this);
- }
例3-使用数组封装参数
为解决例2的问题,我们可以对传入的值进行检查来防止赋值错位的情况发生(反正一般情况下我们都会对传入的值进行检查).然而这并不是解决问题的方法,因为我们要实现的功能还有使程序员可以不按顺序传值.
在弱类型语言中,解决这个问题可以使用 数组 的特殊性,将所有传递的参数封装到数组中,以key=>value键值对的形式保存.请看如下代码:
- class FileUpload
- {
- private $filepath;
- private $allowtype;
- private $maxsize;
- private $israndname;
- function __construct($options=array([默认值]))
- {
- //解析传入的数组
- foreach($options as $key=>$value){
- $this->$key = $value;
- }
- }
这样就解决了传入参数的顺序问题,同时也解决了只传部分参数的问题.
然而新的问题出现了,这时程序员需要输入一个数组作为参数,如下:
- $up = new $FileUpload(array(
- "filepath" => "/upload",
- "israndname" => false,
- "maxsize" => 2000000
- ));
例4-解决参数的大小写
在使用数组封装参数之后,这时需要程序员手动输入变量的名字,这就会因风格不同导致MaxSize, maxSize, maxsize 这样的写法问题,解决这个问题只需要在声明成员变量时都统一用小写,然后在构造函数里加一行:
- foreach($options as $key=>$value){
- $key = strtolower($key);
- ...
- }
到这里,我们的设计已经满足了 友好性目标 中的前三点,整体代码如下:
- class FileUpload {
- private $filepath;
- private $allowtype;
- private $maxsize;
- private $israndname;
- function __construct($options=array(
- "$filepath" => "./",
- "$allowtype" => array("txt","jpg"),
- "$maxsize" => 1000000,
- "$israndname" => true
- )){
- //解析传入的数组
- foreach($options as $key=>$value){
- $key = strtolower($key);
- $this->$key = $value;
- }
- }
- }
例5-处理传入key的错误
在上例中,如果程序员传入了一个类中根本没有的参数,系统会报错,这里我们有两种处理方案:
1. 忽略无效参数,仅执行有效参数
2. 友好的提示出你传入的某个参数无效
个人认为为了程序的健壮性,不能轻易容许错误的代码存在,故选择第二者,我们将这个错误友好的提示给调用者.
- foreach($options as $key=>$value){
- $key = strtolower($key);
- //判断类中是否有这个变量
- if(in_array($key, get_class_vars(get_class($this)))) {
- $this->$key = $value;
- }else{ //提示错误位置和参数
- echo "Error when init class ".get_class($this)." with key: ".$key." in array !";
- exit;
- }
- }
例6-检查传入value是否合法
至此,预期的4个目标均已实现,且为了使__construct()函数具有复用性,使用时可以直接paste,我们将对value的检查抽象成一个函数,请看修改后的代码:
- class FileUpload {
- //变量名均使用小写
- private $filepath;
- private $allowtype;
- private $maxsize;
- private $israndname;
- //在构造函数中赋予默认值
- function __construct($options=array(
- "$filepath" => "./",
- "$allowtype" => array("txt","jpg"),
- "$maxsize" => 1000000,
- "$israndname" => true
- )){
- //解析传入的数组
- foreach($options as $key=>$value){
- $key = strtolower($key);
- //判断key是否在类中声明
- if(in_array($key, get_class_vars(get_class($this)))) {
- //检查value是否符合要求
- if(checkValue($key,$value)) {
- $this->$key = $value;
- } else {
- //提示错误位置和参数
- echo "Invalid value".$value."found when init class ".get_class($this)." with key: ".$key." in array !";
- exit;
- }
- }else{
- //提示错误位置和参数
- echo "Error when init class ".get_class($this)." with key: ".$key." in array !";
- exit;
- }
- }
- }
- function checkValue{
- if(){
- ...
- return true;
- }
- return false;
- }
- }
|