php优雅的获取大量的参数——位掩码

php优雅的获取大量的参数——位掩码

对函数内部进行参数设置是在编码中经常遇见的一个设计问题,一般情况下,我们会有三种方式。

1、2B程序员(没错这就是我经常用的那种)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function a_func($option1, $option2)
{
	if ($option1) {
		//some code
	} else {
		//some code
	}

	if ($option2) {
		//some code
	} else {
		//some code
	}
}

2、普通程序员

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function b_func($options)
{
	if ($options['a']) {
		//some code
	} else {
		//some code
	}

	if ($options['b']) {
		//some code
	} else {
		//some code
	}
}

3、文艺的程序员

没错,今儿我就是要讲讲怎么个文艺法.

3.1、对比一下

作为php程序员json_encode 这个函数肯定是再了解不过了,可是大家了解这个函数的第二个参数吗?

1
2
//像这样
$data_str = json_encode($a, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE);

从 json_encode() 的文档中,我们能得知第二参数的各个选项会对输出来的json字符串有不同的解析方式。

对比一下1和2的用法:

1
2
a_func(true, false) // 如果不知道函数原型的话根本不知道在干什么。
b_func(['a' => true, 'b' => false]) // 如果是第三方用的话不一定知道还有a和b两个参数,还得去源码中找。

3.2、我们如何文艺的设计这样的函数

以我用laravel这么多年的经验来看,内部设计的越精巧复杂,外部用起来就越简单明了。没错,用这种文艺的方法,也会有点复杂。

首先,设计一个解析函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * 解析按位输入的参数
 *
 * @param  int $options     用户选择的参数
 * @param  int $all_options 所有参数
 * @param  int $default     默认值
 * @return int 解析后的内容
 */
function __parse_bitwise_params($options, $all_options, $default = 0)
{
    return $all_options & $options ?: $default;
}

看看使用场景:

假如一个用户模块,我们想获取用户的信息,那么其实我们可以这样写

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * 用户模块
 */
class UserModule
{
    const USER_RAW = 1;
    const USER_STR = 2;
    const USER_ARRAY = 4;

    /**
     * @var User
     */
    protected $user;

    public function getInfo($options = self::INFO_RAW)
    {
        $type = __parse_bitwise_params($options, self::USER_RAW | self::USER_STR | self::USER_ARRAY);

        switch($type){
            case self::USER_RAW:
                return $this->user;
                break;
            case self::USER_STR:
                return $this->user->toString();
                break;
            case self::USER_ARRAY:
                return $this->user->toArray();
                break;
            default:
                return $this->user;
        }
    }
}

看到这,各位看官会问了,这不是拖了裤子**嘛!明明传一个数字进来就OK了.

这个问题问的好,因为这种优(wen)雅(yi)的方式肯定不是用于传一种参数的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
 * 用户模块
 */
class UserModule
{
    const USER_RAW = 1;
    const USER_STR = 2;
    const USER_ARRAY = 4;

    const USER_MSG_ID = 16;
    const USER_MSG_BASE = 32;
    const USER_MSG_ALL = 64;

    /**
     * @var User
     */
    protected $user;

    public function getInfo($options = self::INFO_RAW)
    {
        $msg_type = __parse_bitwise_params($options, self::USER_MSG_ID | self::USER_MSG_BASE | self::USER_MSG_ALL);

        if ($msg_type == self::USER_MSG_ID) {
            return $this->user->id;
        }

        $type = __parse_bitwise_params($options, self::USER_RAW | self::USER_STR | self::USER_ARRAY);

        $get_user_msg = function($opt) {
            if ($opt == self::USER_MSG_BASE) {
                return array_only($this->user->toArray(), ['id', user_name', 'age']);
            } else {
                return $this->user->toArray();
            }
        }

        switch($type){
            case self::INFO_RAW:
                return $this->user;
                break;
            case self::INFO_STR:
                return json_encode($get_user_msg($msg_type));
                break;
            case self::INFO_ARRAY:
                return $get_user_msg($msg_type);
                break;
            default:
                return $this->user;
        }
    }
}

这才是为师的完全体!(不要吐槽那个匿名函数,只是想一个函数写完得了….)

没错,这种写法就是用来传多个参数设计的,那么如果我们使用了这种方案设计代码,外部的调用将会很简单。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//获取user_id
$user_id = $userModule->getInfo(UserModule::INFO_MSG_ID);

//获取User模型
$user = $userModule->getInfo(UserModule::INFO_RAW);

//获取用户的信息数组
$user = $userModule->getInfo(UserModule::USER_ARRAY);

//获取用户的基本数据
$user_base = $userModule->getInfo(UserModule::USER_ARRAY | UserModule::USER_MSG_BASE);

总结:

对于这种模块的设计,这种方案不一定是最好的,因为设计代码的方式千千万,这只是一块砖,希望能对大家的代码设计带来新的灵感。

原创文章,转载请注明出处链接。