IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 从零开始写一个PHP开发框架websocket框架 -> 正文阅读

[网络协议]从零开始写一个PHP开发框架websocket框架

作者:token keyword

前言

本项目基于workerman实现支持websocket、tcp协议的PHP框架,mvc模式,跟传统http框架运行原理相差不多,只是入口依赖于workerman接收到的消息
项目源码可以移步github参考,欢迎star
https://github.com/feixuekeji/flysocket

入口

入口文件是GatewayWorker下Event.php
入口处需要引入下自动加载函数,以便框架里函数调用
require_once DIR . ‘/…/lib/Autoloader.php’;
主要有两个函数
onWorkerStart 项目启动时初始化框架
onMessage 接受到客户端信息,收到消息转发给框架执行请求,相当于收到http请求信息

require_once __DIR__ . '/../lib/Autoloader.php';

/**
     * 进程启动后初始化
     */
    public static function onWorkerStart($worker)
    {
        // 执行应用并响应
        Container::get('app')->init($worker->id);


    }

    /**


   /**
    * 当客户端发来消息时触发
    * @param int $client_id 连接id
    * @param mixed $message 具体消息
    */
   public static function onMessage($client_id, $message)
   {
       if ($message == 'ping')
           return;
       App::run($client_id, $message);
   }

app

app主要包含框架初始化跟执行两个功能
初始化init函数主要功能包括
路由加载,Session,数据库等初始化

运行函数run 负责收到请求后具体执行,
解析请求数据
组装request请求对象
路由分发执行
将执行结果返回客户端

App.php

public function __construct()
    {
        $this->rootPath = __DIR__ . DIRECTORY_SEPARATOR . '../';
        $this->routePath   = $this->rootPath . 'route' . DIRECTORY_SEPARATOR;
        $this->configPath  = $this->rootPath . 'config' . DIRECTORY_SEPARATOR;
        $this->runtimePath = $this->rootPath . 'runtime' . DIRECTORY_SEPARATOR;
    }

    public function run($client_id, $message)
    {
        try {
            $message = json_decode($message,true);
            !is_array($message) && $message = [];
            $request = Container::get('request',[$message]);
            $res = Route::dispatch($request);
            $response = $request->response($res['data'],$res['code'],$res['msg']);
        } catch (\Throwable $e) {
            Error::exception($e);
            $response = $request->response('',$e->getCode() ?: 1,$e->getMessage());
        }
//        Log::info('response',$response);
        // 向当前client_id发送数据
        Gateway::sendToClient($client_id, json_encode($response));
        //清空request
        Container::remove('request');

    }

    /**
     *初始化
     * @author xingxiong.fei@163.com
     * @date 2020-09-03 9:43
     */
    public function init($workerId)
    {
        try {
            $log = Container::get('log',[Config::get('','log')]);
            $cache = Container::get('cache',[Config::get('','cache')]);
            Container::get('session',[Config::get('','session')]);
            //加载路由
            Container::get('route')->import();
            //数据库初始化
            Db::setConfig(Config::get('','database'));
            Db::setCache($cache);
            Db::setLog($log);
            $workerId == 0 && $this->corn();
        } catch (\Exception $e) {
            Error::exception($e);
        }

    }

自动加载

spl_autoload_register(‘\lib\Autoloader::load’); 注册自动加载函数,程序执行时如果该文件没有加载会调用自动加载函数进行文件引入。

采用命名空间方式定义和自动加载类库文件,遵循psr-0规范,只需要给类库正确定义所在的命名空间,并且命名空间的路径与类库文件的目录一致,那么就可以实现类的自动加载
命名空间跟文件路径一致,只需将类名中的斜杠转成反斜杠就是文件所在路径,如果有更多规则,可具体判断加载

如Admin.php的命名空间为 namespace application\admin\controller;则加载的文件路径为application/admin/controller/Admin.php

Autoloader.php

namespace lib;

/**
 * 自动加载
 */
class Autoloader
{
    public static function load($className)
    {
        $classPath = str_replace('\\', '/', $className);
        $classFile = __DIR__ .'/../'.$classPath.'.php';
        if (is_file($classFile)) {
            require_once($classFile);
            if (class_exists($className, false)) {
                return true;
            }
        }
        return false;
    }
}

spl_autoload_register('\lib\Autoloader::load');

路由分发

dispatch函数
根据request请求里的模块、控制器、方法名,拼装出需要调用的类名,
调用目标类
然后使用call_user_func_array调用类中方法执行

import
读取路由配置文件,加载路由表,Request里获取模块名,控制器,方法时用到

Route.php

class Route
{

    /**
     * 路由表
     * @var array
     */
    protected $routeList = [];

    /**
     * 路由分发
     * @param Request $request
     * @return mixed|void
     */
    public static function dispatch(Request $request)
    {
        $module = $request->module();
        $controller = $request->controller();
        $action = $request->action();
        if (!$module || !$controller || !$action)
           throw new \Exception('api  is not exists',100);
        //将api转换为控制器方法的命名空间
        $className = '\\application\\' . $module . '\\controller\\' . ucfirst($controller);
        $obj = new $className($request);
        if (!method_exists($obj, $action))
            throw new \Exception('method ' . $action . ' is not exists',100);
        $res = call_user_func_array(array($obj, $action), array($request));
        return $res;
    }

    /**
     * desc:导入
     * author: xxf<waxiongfeifei@gmail.com>
     * date: 2021/4/22
     * time: 上午11:04
     */
    public function import()
    {
        $path = Container::get('app')->getRoutePath();

        $files = is_dir($path) ? scandir($path) : [];

        foreach ($files as $file) {
            if (strpos($file, '.php')) {
                $filename = $path . DIRECTORY_SEPARATOR . $file;
                // 导入路由配置
                $rules = include $filename;
                if (is_array($rules)) {
                    $this->routeList = array_merge($this->routeList,$rules);
                }
            }
        }
    }



    public function getRoute($api)
    {
        if (array_key_exists($api, $this->routeList))//获取真实路径
            $api = $this->routeList[$api];
        return $api;
    }
}

请求

主要功能包括请求信息(如IP,端口,参数)的初始化以及参数的获取安全过滤,以供在控制起来使用
本项目里自定义请求信息如下,以json文本形式传输

$param = [
            'api' => 'my-info',//接口地址
            'app' => 'iphone',//客户端设备
            'ver' => '1.0',//版本号
            'data' => [//具体数据
            ],
        ];

Request.php

    private static $_instance; //存储对象

    public function __construct(array $options = [])
    {
        $this->init($options);
        self::$_instance = $this;
    }


    public function init(array $options = [])
    {
        $this->filter = Config::get('default_filter');
        $this->param = $options['data'] ?? [];
        $this->api =  $options['api'] ?? '';
        $this->route =  $options['api'] ?? '';
        $this->app =  $options['app'] ?? '';
        $this->ver =  $options['ver'] ?? '';
        $this->route = Container::get('route')->getRoute($this->route);
        $api = explode('/',$this->route);
        $this->setModule($api[0] ?? '');
        $this->setController($api[1] ?? '');
        $this->setAction($api[2] ?? '');
        $this->ip =  $this->ip();
        $this->setPort();
        $this->setGatewayIp();
        $this->setGatewayPort();
        $this->setClientId();
        \lib\facade\Log::info('request',get_object_vars($this));
    }

配置文件

用于从文件里获取配置信息

Config.php

class Config
{
    protected static $config;

    // 加载配置文件
    static function load($file){
        if (!isset(self::$config[$file])){
            $confFile = __DIR__ . '/../config/' . $file .'.php';
            if (is_file($confFile)){
                self::$config[$file] = include_once $confFile;
            }
        }

    }




    /**
     *获取配置参数 为空则获取所有配置
     * @param null $name
     * @param string $file
     * @param null $default
     * @return |null
     * @author xingxiong.fei@163.com
     * @date 2020-08-26 16:22
     */
    public static function get($name = null,$file = 'config', $default = null)
    {
        self::load($file);
        // 无参数时获取所有
        if (empty($name)) {
            return self::$config[$file];
        }
        $name    = explode('.', $name);
        $name[0] = strtolower($name[0]);
        $config  = self::$config[$file];
        // 按.拆分成多维数组进行判断
        foreach ($name as $val) {
            if (isset($config[$val])) {
                $config = $config[$val];
            } else {
                return $default;
            }
        }
        return $config;
    }

redis

Redis.php

class Redis
{

    private static $_instance; //存储对象
    private function __construct( ){
        $config = Config::get('redis');
        self::$_instance = new \Redis();
        //从配置读取
        self::$_instance->connect($config['host'], $config['port']);
        self::$_instance->select($config['db_index']);
        if ('' != $config['password']) {
            self::$_instance->auth($config['password']);
        }

    }




    public static function getInstance( )
    {
        if (!self::$_instance) {
            new self();
        }
        else{
            try {
                @trigger_error('flag', E_USER_NOTICE);
                self::$_instance->ping();
                $error = error_get_last();
                if($error['message'] != 'flag')
                    throw new \Exception('Redis server went away');
            } catch (\Exception $e) {
                // 断线重连
                new self();
            }
        }
        return self::$_instance;
    }





    /**
    * 禁止clone
    */
    private function __clone(){}

    /**
     * 其他方法自动调用
     * @param $method
     * @param $args
     * @return mixed
     */
    public function __call($method,$args)
    {
        return call_user_func_array([self::$_instance, $method], $args);
    }

    /**
     * 静态调用
     * @param $method
     * @param $args
     * @return mixed
     */
    public static function __callStatic($method,$args)
    {
        self::getInstance();
        return call_user_func_array([self::$_instance, $method], $args);
    }


缓存

缓存遵循psr-16规范,本项目里只支持Redis的实现

Cache.php

/**
 * 缓存类
 * Class Cache
 * @package lib
 */
class Cache implements Psr16CacheInterface
{
    /**
     * 驱动句柄
     * @var object
     */
    protected $handler = null;

    /**
     * 缓存参数
     * @var array
     */
    protected $options = [
        'expire'     => 0,
        'prefix'     => '',
        'serialize'  => true,
    ];
    public function __construct($options = []){
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
    }



    /**
     * {@inheritdoc}
     */
    public function get($name, $default = null)
    {
        $this->handler = Redis::getInstance();
        $key    = $this->getCacheKey($name);
        $value = $this->handler->get($key);
        if (is_null($value) || false === $value) {
            return $default;
        }
        return $this->unserialize($value);
    }

    /**
     * 写入缓存
     * @access public
     * @param  string            $name 缓存变量名
     * @param  mixed             $value  存储数据
     * @param  integer|\DateTime $expire  有效时间(秒)
     * @return boolean
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function set($name, $value, $expire = null)
    {
        $this->handler = Redis::getInstance();
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
        $value = $this->serialize($value);
        $key    = $this->getCacheKey($name);
        if ($expire) {
            $result = $this->handler->setex($key, $expire, $value);
        } else {
            $result = $this->handler->set($key, $value);
        }
        return $result;

    }

    /**
     * 批量获取
     * @param iterable $keys
     * @param null $default
     * @return array|iterable
     * @throws \Psr\SimpleCache\InvalidArgumentException
     */
    public function getMultiple($keys, $default = null)
    {
        if (!\is_array($keys)) {
            throw new \Exception(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
        }
        $result = [];
        foreach ($keys as $key) {
            $result[$key] = $this->get($key);
        }
        return $result;

    }

    /**
     *批量设置
     * @param iterable $values
     * @param null $expire
     * @return bool
     * @throws \Exception
     * @author xxf
     * @date 2020-08-26 15:37
     */
    public function setMultiple($values, $expire = null)
    {
        if (!\is_array($values)) {
            throw new \Exception(sprintf('Cache values must be array or Traversable, "%s" given', \is_object($values) ? \get_class($values) : \gettype($values)));
        }
        if (is_null($expire)) {
            $expire = $this->options['expire'];
        }
        try {
            foreach ($values as $key => $value) {
                if (\is_int($key)) {
                    $key = (string) $key;
                }
                $this->set($key,$value,$expire);
            }
            return true;
        } catch (\Exception $e) {
            return false;
        }

    }

    /**
     * 删除缓存
     * @access public
     * @param  string $name 缓存变量名
     * @return boolean
     */
    public function delete($name)
    {
        $this->handler = Redis::getInstance();
        $key = $this->getCacheKey($name);
        try {
            $this->handler->del($key);
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function deleteMultiple($keys)
    {
        $this->handler = Redis::getInstance();
       if (!\is_array($keys)) {
            throw new Exception(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys)));
        }
       foreach ($keys as &$item){
           $item = $this->getCacheKey($item);
       }

        try {
            $this->handler->del($keys);
            return true;
        } catch (\Exception $e) {
            return false;
        }



    }

    /**
     * 清除缓存
     * @access public
     * @param  string $tag 标签名
     * @return boolean
     */
    public function clear()
    {
        $this->handler = Redis::getInstance();
        return $this->handler->flushDB();
    }




    /**
     * 判断缓存
     * @access public
     * @param  string $name 缓存变量名
     * @return bool
     */
    public function has($name)
    {
        $this->handler = Redis::getInstance();
        $key = $this->getCacheKey($name);
        return $this->handler->exists($key);
    }


    /**
     * 序列化数据
     * @access protected
     * @param  mixed $data
     * @return string
     */
    protected function serialize($data)
    {
        if (is_scalar($data) || !$this->options['serialize']) {
            return $data;
        }
        $data = 'serialize:'.serialize($data);
        return $data;
    }

    /**
     * 反序列化数据
     * @access protected
     * @param  string $data
     * @return mixed
     */
    protected function unserialize($data)
    {
        if ($this->options['serialize'] && 0 === strpos($data, 'serialize:')) {
            return unserialize(substr($data, 10));
        } else {
            return $data;
        }
    }

    /**
     * 获取实际的缓存标识
     * @access protected
     * @param  string $name 缓存名
     * @return string
     */
    protected function getCacheKey($name)
    {
        return $this->options['prefix'] . $name;
    }

数据库ORM

ORM自己造轮子有点复杂就使用了ThinkOrm,大多数方法跟tp一致

日志

日志日志遵循PSR-3规范基于Monolog实现

Log.php

class Log implements LoggerInterface
{

    protected $loggers;


    /**
     * 是否允许日志写入
     * @var bool
     */
    protected $allowWrite = true;

    protected $config = [
        'path'        => '',
        // 日志通道名
        'channel'        => 'app',
        'level' => 'debug',
        'max_files'   => 0,
        'file_permission'  => 0666,
        'sql_level'  => 'info',
    ];

    // 实例化并传入参数
    public function __construct($config = [])
    {

        if (is_array($config)) {
            $this->config = array_merge($this->config, $config);
        }
        if (!empty($config['close'])) {
            $this->allowWrite = false;
        }

        if (empty($this->config['path'])) {
            $this->config['path'] = \lib\facade\App::getRootPath() . 'runtime/logs' . DIRECTORY_SEPARATOR;
        } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) {
            $this->config['path'] .= DIRECTORY_SEPARATOR;
        }
    }



    private function createLogger($name,$fileName = '')
    {
        if (empty($this->loggers[$name.$fileName])) {
            // 根据业务域名与方法名进行日志名称的确定
            $channel       = $this->config['channel'];
            // 日志文件目录
            $path       = $this->config['path'];
            // 日志保存时间
            $maxFiles       = $this->config['max_files'];
            // 日志等级
            $level = Logger::toMonologLevel($this->config['level']);
            // 权限
            $filePermission =  $this->config['file_permission'];
            // 创建日志
            $logger    = new Logger($channel);
            // 日志文件相关操作
            $logFileName = empty($fileName) ? $name : $name . '-' .$fileName;
            $handler   = new RotatingFileHandler("{$path}{$logFileName}.log", $maxFiles, $level, true, $filePermission);
            // 日志格式
            $formatter = new LineFormatter("%datetime% %channel%:%level_name% %message% %context% %extra%\n", "Y-m-d H:i:s", false, true);

            $handler->setFormatter($formatter);
            $logger->pushHandler($handler);

            $this->loggers[$name.$fileName] = $logger;
        }
        return $this->loggers[$name.$fileName];
    }



    /**
     * 记录日志信息
     * @access public
     * @param  mixed  $message       日志信息
     * @param  string $level      日志级别
     * @param  array  $context   替换内容
     * @param string $fileName  文件名
     * @return $this
     */
    public function record($message, $level = 'info', array $context = [],$fileName = '')
    {
        if (!$this->allowWrite) {
            return;
        }
        $logger = $this->createLogger($level,$fileName);
        $level = Logger::toMonologLevel($level);
        if (!is_int($level)) $level = Logger::INFO;
        // $backtrace数组第$idx元素是当前行,第$idx+1元素表示上一层,另外function、class需再往上取一个层次
        // PHP7 不会包含'call_user_func'与'call_user_func_array',需减少一层
        if (version_compare(PCRE_VERSION, '7.0.0', '>=')) {
            $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
            $idx       = 0;
        } else {
            $backtrace = debug_backtrace();
            $idx       = 1;
        }
        $trace = basename($backtrace[$idx]['file']) . ":" . $backtrace[$idx]['line'];
        if (!empty($backtrace[$idx + 1]['function'])) {
            $trace .= '##';
            $trace .= $backtrace[$idx + 1]['function'];
        }
        $message = sprintf('==> LOG: %s -- %s', $message, $trace);
        return $logger->addRecord($level, $message, $context);
    }




    /**
     * 记录日志信息
     * @access public
     * @param  string $level     日志级别
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function log($level, $message, array $context = [], $fileName = '')
    {
        if ($level == 'sql')
            $level = $this->config['sql_level'];
        $this->record($message, $level, $context, $fileName);
    }

    /**
     * 记录emergency信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function emergency($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录警报信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function alert($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录紧急情况
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function critical($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录错误信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function error($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录warning信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function warning($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录notice信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * * @param string $fileName
     * @return void
     */
    public function notice($message, array $context = [],$fileName = '')
    {
        $this->log(__FUNCTION__, $message, $context, $fileName);
    }

    /**
     * 记录一般信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @param string $fileName
     * @return void
     */

    public function info($message, array $context = [],$fileName = '')
    {
        $this->log(__FUNCTION__, $message, $context, $fileName);
    }

    /**
     * 记录调试信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function debug($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

    /**
     * 记录sql信息
     * @access public
     * @param  mixed  $message   日志信息
     * @param  array  $context   替换内容
     * @return void
     */
    public function sql($message, array $context = [])
    {
        $this->log(__FUNCTION__, $message, $context);
    }

容器

session

主要包括session的读写功能

Session.php

public function __construct(array $config = [])
    {
        $this->config = $config;
    }

    /**
     * 设置或者获取session作用域(前缀)
     * @access public
     * @param  string $prefix
     * @return string|void
     */
    public function prefix($prefix = '')
    {
        if (empty($prefix) && null !== $prefix) {
            return $this->prefix;
        } else {
            $this->prefix = $prefix;
        }
    }

    public static function __make(Config $config)
    {
        return new static($config->get('','session'));
    }

    /**
     * 配置
     * @access public
     * @param  array $config
     * @return void
     */
    public function setConfig(array $config = [])
    {
        $this->config = array_merge($this->config, array_change_key_case($config));

        if (isset($config['prefix'])) {
            $this->prefix = $config['prefix'];
        }
    }


    /**
     * session初始化
     * @access public
     * @param  array $config
     * @return void
     * @throws \think\Exception
     */
    public function init(array $config = [])
    {
        $config = $config ?: $this->config;

        if (isset($config['prefix'])) {
            $this->prefix = $config['prefix'];
        }
        $this->init = true;
        return $this;
    }

    /**
     *设置session
     * @param $name
     * @param $value
     * @param null $prefix
     * @throws \think\Exception
     * @date 2020-09-10 14:26
     */
    public function set($name, $value, $prefix = null)
    {
        is_null($this->init) && $this->init();
        $prefix = !is_null($prefix) ? $prefix : $this->prefix;
        if (strpos($name, '.')) {
            // 二维数组赋值
            list($name1, $name2) = explode('.', $name);
            if ($prefix) {
                $_SESSION[$prefix][$name1][$name2] = $value;
            } else {
                $_SESSION[$name1][$name2] = $value;
            }
        } elseif ($prefix) {
            $_SESSION[$prefix][$name] = $value;
        } else {
            $_SESSION[$name] = $value;
        }
    }

    /**
     *获取
     * @param string $name
     * @param null $prefix
     * @return array|mixed|null
     * @throws \think\Exception
     * @date 2020-09-10 14:26
     */
    public function get($name = '', $prefix = null)
    {

        is_null($this->init) && $this->init();

        $prefix = !is_null($prefix) ? $prefix : $this->prefix;

        $value = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION;

        if ('' != $name) {
            $name = explode('.', $name);

            foreach ($name as $val) {
                if (isset($value[$val])) {
                    $value = $value[$val];
                } else {
                    $value = null;
                    break;
                }
            }
        }
        return $value;
    }


    /**
     *获取后删除
     * @param $name
     * @param null $prefix
     * @return array|mixed|void|null
     * @throws \think\Exception
     * @date 2020-09-10 14:27
     */
    public function pull($name, $prefix = null)
    {
        $result = $this->get($name, $prefix);

        if ($result) {
            $this->delete($name, $prefix);
            return $result;
        } else {
            return;
        }
    }


    /**
     *删除
     * @param $name
     * @param null $prefix
     * @throws \think\Exception
     * @author xingxiong.fei@163.com
     * @date 2020-09-10 14:24
     */
    public function delete($name, $prefix = null)
    {
        is_null($this->init) && $this->init();

        $prefix = !is_null($prefix) ? $prefix : $this->prefix;

        if (is_array($name)) {
            foreach ($name as $key) {
                $this->delete($key, $prefix);
            }
        } elseif (strpos($name, '.')) {
            list($name1, $name2) = explode('.', $name);
            if ($prefix) {
                unset($_SESSION[$prefix][$name1][$name2]);
            } else {
                unset($_SESSION[$name1][$name2]);
            }
        } else {
            if ($prefix) {
                unset($_SESSION[$prefix][$name]);
            } else {
                unset($_SESSION[$name]);
            }
        }
    }

    /**
     *清空
     * @param null $prefix
     * @throws \think\Exception
     * @author xingxiong.fei@163.com
     * @date 2020-09-10 14:25
     */
    public function clear($prefix = null)
    {
        is_null($this->init) && $this->init();
        $prefix = !is_null($prefix) ? $prefix : $this->prefix;

        if ($prefix) {
            unset($_SESSION[$prefix]);
        } else {
            $_SESSION = [];
        }
    }

    /**
     *判断是否存在
     * @param $name
     * @param null $prefix
     * @return bool
     * @throws \think\Exception
     * @author xingxiong.fei@163.com
     * @date 2020-09-10 14:22
     */
    public function has($name, $prefix = null)
    {
        is_null($this->init) && $this->init();
        $prefix = !is_null($prefix) ? $prefix : $this->prefix;
        $value  = $prefix ? (!empty($_SESSION[$prefix]) ? $_SESSION[$prefix] : []) : $_SESSION;

        $name = explode('.', $name);

        foreach ($name as $val) {
            if (!isset($value[$val])) {
                return false;
            } else {
                $value = $value[$val];
            }
        }
        return true;
    }

    /**
     *追加到session数组
     * @param $key
     * @param $value
     * @throws \think\Exception
     * @date 2020-09-10 14:28
     */
    public function push($key, $value)
    {
        $array = $this->get($key);

        if (is_null($array)) {
            $array = [];
        }
        $array[] = $value;

        $this->set($key, $array);
    }

异常

用来注册异常处理函数,捕捉全局异常并记录错误日志
Error.php

class Error
{
    /**
     * 配置参数
     * @var array
     */
    protected static $exceptionHandler;

    /**
     * 注册异常处理
     * @access public
     * @return void
     */
    public static function register()
    {
        error_reporting(E_ALL);
        set_error_handler([__CLASS__, 'error']);
        set_exception_handler([__CLASS__, 'exception']);
        register_shutdown_function([__CLASS__, 'shutdown']);
    }

    /**
     *
     * @param $e
     * @author xingxiong.fei@163.com
     * @date 2020-09-02 17:36
     */
    public static function exception($e)
    {
        self::report($e);
    }

    public static function report(Throwable $exception)
    {
        $data = [
            'file'    => $exception->getFile(),
            'line'    => $exception->getLine(),
            'message' => $exception->getMessage(),
            'code'    => $exception->getCode(),
        ];
        \lib\facade\Log::error('错误信息',$data);
        \lib\facade\Log::error('错误跟踪',$exception->getTrace());
    }

    /**
     * Error Handler
     * @access public
     * @param  integer $errno   错误编号
     * @param  integer $errstr  详细错误信息
     * @param  string  $errfile 出错的文件
     * @param  integer $errline 出错行号
     * @throws ErrorException
     */
    public static function error($errno, $errstr, $errfile = '', $errline = 0): void
    {
        $data = [
            'file'    => $errfile,
            'line'    =>$errline,
            'message' => $errstr,
            'code'    => $errno,
        ];
        \lib\facade\Log::error('错误信息',$data);

    }

    public static function errorLog(\Error $error): void
    {
        $data = [
            'file'    => $error->getFile(),
            'line'    => $error->getLine(),
            'message' => $error->getMessage(),
            'code'    => $error->getCode(),
        ];
        \lib\facade\Log::error('错误信息',$data);
    }

    /**
     * Shutdown Handler
     * @access public
     */
    public static function shutdown()
    {

        if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {

            self::error($error);
        }
    }

    /**
     * 确定错误类型是否致命
     *
     * @access protected
     * @param  int $type
     * @return bool
     */
    protected static function isFatal($type)
    {
        return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
    }

控制器

控制器基类 初始化时依赖注入Request对象,继承该类的控制器可直接使用。

Controlle.php

class Controller
{

    /**
     * Request实例
     * @var \think\Request
     */
    protected $request;

    /**
     * 构造方法
     * @access public
     */
    public function __construct(Request $request)
    {
        $this->request = Container::get('request');
        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {}


}

使用方法

移步 https://www.kancloud.cn/xiongfeifei/ver1/2131252

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-06-01 15:28:43  更:2022-06-01 15:28:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 16:01:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码