那时候刚好下着雨,柏油路面湿冷冷的,还闪烁着青、黄、红颜色的灯火。



Symfony 中的 Services


Symfony 中的 Services

两个小例子来说明symfony中如何自写义自己的services,真的非常简单。

What is a Service?

官方文档是这么说的:

Put simply, a service is any PHP object that performs some sort of "global" task. It's a purposefully-generic name used in computer science to describe an object that's created for a specific purpose (e.g. delivering emails). Each service is used throughout your application whenever you need the specific functionality it provides. You don't have to do anything special to make a service: simply write a PHP class with some code that accomplishes a specific task. Congratulations, you've just created a service!

大概的意思是: 服务是某种“全局”的PHP对象。它是在计算机科学中用于描述对特定目的(例如提供电子邮件)创建的对象的目的地 - 通用名称。当你需要它提供的特定功能,每个服务在整个应用程序使用。你不必做其他特殊的操作使服务:只需编写一个PHP类,完成特定的任务。

``

创建、配制一个服务

比如我现在有一个生成短链接的类:

// src/AppBundle/Utils/ShortUrl.php

namespace AppBundle\Utils;

/**
 * Class ShortUrl
 * @package AppBundle\Utils
 */
class ShortUrl
{
    /**
     * 字符表
     *
     * @var string
     */
    public $charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    /**
     * @param $url
     * @param string $baseUrl
     * @return array
     */
    public function short($url, $baseUrl = '')
    {
        $key = "alexis";
        $urlHash = md5($key . $url);
        $len = strlen($urlHash);

        $short_url_list = [];

        // 将加密后的串分成4段,每段4字节,对每段进行计算,一共可以生成四组短连接
        for ($i = 0; $i < 4; $i++) {
            $urlHash_piece = substr($urlHash, $i * $len / 4, $len / 4);
            // 将分段的位与0x3fffffff做位与,0x3fffffff表示二进制数的30个1,即30位以后的加密串都归零
            $hex = hexdec($urlHash_piece) & 0x3fffffff; #此处需要用到hexdec()将16进制字符串转为10进制数值型,否则运算会不正常

            // 生成6位短连接
            for ($j = 0; $j < 6; $j++) {
                // 将得到的值与0x0000003d,3d为61,即charset的坐标最大值
                $baseUrl .= $this->charset[$hex & 0x0000003d];
                // 循环完以后将hex右移5位
                $hex = $hex >> 5;
            }

            $short_url_list[] = $baseUrl;
        }

        return $short_url_list;
    }
}

那如何使上面这个类成为symfony中的一个服务呢?

下面一个简单的例子来说明:

打开app/config/services.yml文件在 services下加入

# app/config/services.yml
services:
    app.utils.shortUrl: # 命名推荐使用 {bundle}.{服务名称}
        class:        AppBundle\Utils\ShortUrl
        # arguments:    [] # 因为这需要依赖其他服务,所以arguments为空就行了,如果需要注入其他服务的话按官方文档写就行了。

使用这个服务

咱们在 src/AppBundle/Controller/DefaultController.php 文件的 indexAction方法加入以下代码:

public function indexAction(Request $request)
{
    $shareUrl = $this->get('app.utils.shortUrl');
    $shorts = $shareUrl->short($this->generateUrl('photo_index', ['sign' => $photo->getUuid()], UrlGeneratorInterface::ABSOLUTE_URL));
    
    dump($shorts[0]); // 它返回的是一个多维数组,下标 0 就是最短的6位
}

来一个需要注入其他服务的例子

先写一个ip的服务

// src/AppBundle/Utils/IP.php
namespace AppBundle\Utils;

/**
 * Class IP
 * @package AppBundle\Utils
 */
class IP
{
    /**
     * ip to long
     *
     * @param string $ip
     * @return int
     */
    public function ipToLong($ip)
    {
        return bindec(decbin(ip2long($ip)));
    }

    /**
     * reset ip
     *
     * @param $decimal
     * @return string
     */
    public function resetIp($decimal)
    {
        return long2ip($decimal);
    }

    /**
     * check ip
     *
     * @param $address
     * @return mixed
     */
    public function checkIP($address)
    {
        return filter_var($address, FILTER_VALIDATE_IP);
    }
}

再写一个需要注入其他服务的类

// src/AppBundle/Utils/RedisClient.php
namespace AppBundle\Utils;


use AppBundle\Entity\Address;
use Monolog\Logger;
use Symfony\Component\HttpFoundation\JsonResponse;

/**
 * Class RedisClient
 * @package AppBundle\Utils
 */
class RedisClient
{
    /**
     * @var \Redis
     */
    private $redis;

    /**
     * @var IP
     */
    private $IP;

    /**
     * @var Logger
     */
    private $logger;

    /**
     * @var array
     */
    private $filter = [
        'KEYS', 'GET', 'HGET', 'HGETALL', 'DEL', 'AUTH', 'SORT', 'ZADD', 'SADD', 'LPOP', 'HLEN', 'HMSET', 'TTL', 'TYPE', 'INCR', 'HDEL', 'EXISTS',
        'SELECT', 'HEXISTS', 'INCRBY', 'MSET', 'MSETNX', 'SETBIT', 'SETEX', 'SETNX', 'BLPOP', 'QUIT', 'TIME', 'ECHO', 'ZCARD', 'LPUSH', 'LPUSHX', 'RPOP',
        'EXPIRE', 'MIGRATE', 'GETBIT', 'GETRANGE', 'GETSET', 'MGET', 'HMGET', 'RESTORE', 'APPEND', 'HKEYS', 'HSET', 'HSETNX', 'HSTRLEN', 'BRPOP', 'BLPOP',
        'LINDEX', 'LINSERT', 'LLEN', 'LRANGE', 'LREM', 'LSET', 'RPOP', 'LTRIM', 'ZCARD', 'ZCOUNT', 'ZINCRBY', 'ZRANGE', 'PUBLISH', 'PUBSUB', 'EVAL',
        'INFO', 'SAVE'
    ];

    /**
     * RedisClient constructor.
     * @param IP $IP
     * @param Logger $logger
     */
    public function __construct(IP $IP, Logger $logger)
    {
        $this->redis = new \Redis();
        $this->IP = $IP;
        $this->logger = $logger;
    }

    /**
     * @param Address $address
     * @param int $db
     * @return \Redis|JsonResponse
     */
    public function checkConn(Address $address, $db = 0)
    {
        try {
            if (!$this->redis->connect($this->IP->resetIp($address->getIpAddress()), $address->getPort(), 5)) {
//            if (!$this->redis->connect('10.141.4.80', $address->getPort(), 5)) {
                return new JsonResponse([
                    'success' => false,
                    'message' => '连接失败',
                    'errorCode' => 'REDIS_AUTH_00001'
                ], 400, ['Access-Control-Allow-Origin' => '*']);
            }
        } catch (\RedisException $e) {
            return new JsonResponse([
                'success' => false,
                'message' => $e->getMessage(),
                'errorCode' => 'REDIS_AUTH_00001'
            ], 400, ['Access-Control-Allow-Origin' => '*']);
        }

        if ($address->getAuth()) {
            try {
                $this->redis->auth($address->getPassword());
            } catch (\RedisException $e) {
                return new JsonResponse([
                    'success' => false,
                    'message' => $e->getMessage(),
                    'errorCode' => 'REDIS_AUTH_00001'
                ], 400, ['Access-Control-Allow-Origin' => '*']);
            }
        }

        try {

            $this->redis->select($db);
        } catch (\RedisException $e) {
            return new JsonResponse([
                'success' => false,
                'message' => $e->getMessage(),
                'errorCode' => 'REDIS_AUTH_00001'
            ], 400, ['Access-Control-Allow-Origin' => '*']);
        }

        return $this->redis;
    }

    /**
     * @param $filter
     * @return bool
     */
    public function inFilter($filter)
    {
        return in_array(strtoupper(trim($filter)), $this->filter);
    }

    /**
     * @param $key
     * @param array $args
     * @return array
     */
    public function __call($key, array $args)
    {
        $args = $args[0];
        unset($args[0]);
        $this->logger->info("__call function.", ['key' => $key, 'args' => $args]);

        $response = [];

        try {
            switch (count($args)) {
                case 1:
                    $response = $this->redis->$key($args[1]);
                    break;
                case 2:
                    $response = $this->redis->$key($args[1], $args[2]);
                    break;
                case 3:
                    $response = $this->redis->$key($args[1], $args[2], $args[3]);
                    break;
                case 4:
                    $response = $this->redis->$key($args[1], $args[2], $args[3], $args[4]);
                    break;
            }
        } catch (\RedisException $e) {
            return new JsonResponse([
                'success' => false,
                'message' => $e->getMessage(),
                'errorCode' => 'REDIS_AUTH_00001'
            ], 400, ['Access-Control-Allow-Origin' => '*']);
        }

        $return = [];
        if (is_array($response)) {
            foreach ($response as $item) {
                $return[] = $item;
            }
        } else if (is_string($response)) {
            $return[] = utf8_decode($response);
        }
        $this->redis->close();
        return $return;
    }
}

把这个类加入到服务中

# app/config/services.yml
services:
    app.utils.IP:
        class:        AppBundle\Utils\IP
    app.utils.redisClient:
         class: AppBundle\Utils\RedisClient
         arguments: ["@app.utils.ip", "@monolog.logger"] # 这里需要注入两个服务 一个是自己写的一个 一个是系统自带的logger服务
         # calls: 这个以后再演示
            # - [infoAction, [@app.utils.IP]] # 实例划后自动调用的方法
         # tags: # 这个以后再说 

然后就可以愉快的使用自己定义服务啦!

$redisClient = $this->get('app.utils.redisClient');

$redis = $redisClient->checkConn($addressInfo);

if ($redis instanceof JsonResponse) {
   return $redis;
}

 标签 , TAG , 啦啦