PHP __call() 方法的一种妙用

PHP __call()

在对象中调用一个不可访问方法时,__call() 会被调用。

示例

废话不多说,直接上代码。

<?php

namespace AppThirdPartyRequest;

use Exception;
use GuzzleHttpClient;
use GuzzleHttpExceptionGuzzleException;

/**
 * @method wxPayment(array $params)
 * @method zfbPayment(array $params)
 * @method couponPayment(array $params)
 */
class PayRequest
{
    // 接口地址
    protected $baseUri = "https://www.xxx.com";

    // 请求客户端
    protected $client = NULL;

    // 可供访问的接口集合
    protected $uriMap = [
        'wxPayment'     => '/v1/wx_payment',
        'zfbPayment'    => '/v1/zfb_payment',
        'couponPayment' => '/v1/coupon_payment',
    ];

    /**
     * HTTP Client 发送请求
     *
     * @param string $uri
     * @param array  $params
     *
     * @return array
     * @throws Exception|GuzzleException
     */
    protected function send(string $uri, array $params): array
    {
        // 根据使用自己项目中的 HTTP Client,当前以 GuzzleHttp 为例,示例代码如下:

        if (is_null($this->client)) {
            $this->client = new Client(['base_uri' => $this->baseUri]);
        }

        $response = $this->client->request('POST', $uri, $params);

        if ($response->getStatusCode() == 200) {
            $result = $response->getBody()->getContents();
            return json_decode($result, TRUE);
        }

        throw new Exception($response->getBody()->getContents());
    }

    /**
     * 在对象中调用一个不可访问的方法时调用
     *
     * @param string $method
     * @param array  $arguments
     *
     * @return array
     * @throws Exception|GuzzleException
     */
    public function __call(string $method, array $arguments)
    {
        $methods = array_keys($this->uriMap);
        if (!in_array($method, $methods)) {
            throw new Exception('不支持的方法');
        }

        return $this->send($this->uriMap[$method], ...$arguments);
    }
}

调用方式:

(new PayRequest())->wxPayment(['amount' => 1000]);

(new PayRequest())->zfbPayment(['amount' => 1000]);

(new PayRequest())->couponPayment(['amount' => 1000]);

这种写法有个好处,当再增加新接口调用的时候,只需简单配置下即可。

比如,需要新增加银行卡支付,只需要在 $uriMap 中增加:

'bankCardPayment' => '/v1/bank_card_payment',

最好再增加一行注释,这样便于编辑器代码提示,不增加也不影响代码运行。

* @method bankCardPayment(array $params)

说完了,就到这吧。