本项目基于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()
{
}
}