// 绑定的属性
protected $bind = [];// 邦定的属性 仓库

/**
* 架构函数
* @access public
* @param array $options 参数
*/
public function __construct($options = [])
{// 构造函数
foreach ($options as $name => $item) {// 参数设定
if (property_exists($this, $name)) {// 如果存在合适的参数
$this->$name = $item;// 进行设置 否则不管
}
}
if (is_null($this->filter)) {// 如果为空
$this->filter = Config::get('default_filter');// 配置 获取 当前默认的 配置选项
}
}

public function __call($method, $args)// 调用 动态调用 不存在的函数
{
if (array_key_exists($method, self::$hook)) {// 如果 钩子函数 里面存在的话
array_unshift($args, $this);// 去掉里面这里 参数
return call_user_func_array(self::$hook[$method], $args);// 调用 钩子
} else {// 否则抛出异常
throw new Exception('method not exists:' . __CLASS__ . '->' . $method);
}
}

/**
* Hook 方法注入
* @access public
* @param string|array $method 方法名
* @param mixed $callback callable
* @return void
*/
public static function hook($method, $callback = null)
{// Hook 方法 注入
if (is_array($method)) {// 如果是数组
self::$hook = array_merge(self::$hook, $method);// 更多hook 函数 调度,所谓的注入,其实跟我们的 类似
} else {
self::$hook[$method] = $callback;// 对应的 key value 的设置形式
}
}

/**
* 初始化
* @access public
* @param array $options 参数
* @return \think\Request
*/
public static function instance($options = [])
{// 初始化 单列 模式初始化
if (is_null(self::$instance)) {
self::$instance = new static($options);
}
return self::$instance;
}

/**
* 创建一个URL请求
* @access public
* @param string $uri URL地址
* @param string $method 请求类型
* @param array $params 请求参数
* @param array $cookie
* @param array $files
* @param array $server
* @param string $content
* @return \think\Request
*/
public static function create($uri, $method = 'GET', $params = [], $cookie = [], $files = [], $server = [], $content = null)
{// 创建 URL 里面的 URL 地址 method 方法 请求参数 cookie 文件 files 文件 server 服务 content 内容
$server['PATH_INFO'] = '';// 用小的 server 代替系统变量里面的 SERVER
$server['REQUEST_METHOD'] = strtoupper($method);// 获取 方法 字符串 全部转换成为大写
$info = parse_url($uri);// 解析传递过来的 url
if (isset($info['host'])) {// 如果设置了 host
$server['SERVER_NAME'] = $info['host'];// 域名
$server['HTTP_HOST'] = $info['host'];// ip 变成相同的 产品
}
if (isset($info['scheme'])) {// 如果存在计划 跟 调度
if ('https' === $info['scheme']) {
$server['HTTPS'] = 'on';// 开启安全传输
$server['SERVER_PORT'] = 443;// 443
} else {
unset($server['HTTPS']);// 删除 安全传输
$server['SERVER_PORT'] = 80;// 默认 80端口
}
}
if (isset($info['port'])) {// 如果 设置了 端口 目的 是 非 80端口
$server['SERVER_PORT'] = $info['port'];// 给予系统端口
$server['HTTP_HOST'] = $server['HTTP_HOST'] . ':' . $info['port'];// IP 预计进行了拼合,变成了 IP+ 端口
}
if (isset($info['user'])) {// 如果设置了 用户
$server['PHP_AUTH_USER'] = $info['user'];
}
if (isset($info['pass'])) {// 密码
$server['PHP_AUTH_PW'] = $info['pass'];
}
if (!isset($info['path'])) {// 路径
$info['path'] = '/';
}
$options = [];// 初始化选项仓库
$queryString = '';// 查询字符串 应该就是留在后面的字符串
if (isset($info['query'])) {// 如果给定了 参数
parse_str(html_entity_decode($info['query']), $query);// 解析参数
if (!empty($params)) {//如果传出的参数还有
$params = array_replace($query, $params);// 替换参数
$queryString = http_build_query($query, '', '&');// 创建 queryString
} else {// 否则 默认的 没有对应设置的参数
$params = $query;
$queryString = $info['query'];// 他就是 对应的字符串
}
} elseif (!empty($params)) {
$queryString = http_build_query($params, '', '&');// 通过参数 设置 对应的 字符串
}
$server['REQUEST_URI'] = $info['path'] . ('' !== $queryString ? '?' . $queryString : '');// 后面的参数 是空,还是 带有问号的参数
$server['QUERY_STRING'] = $queryString;// 请求的字符串
$options['cookie'] = $cookie;// cookie
$options['param'] = $params;// 参数
$options['file'] = $files;// 文件
$options['server'] = $server;// 服务
$options['url'] = $server['REQUEST_URI']; // 简写
$options['baseUrl'] = $info['path'];// 基础路径
$options['pathinfo'] = '/' == $info['path'] ? '/' : ltrim($info['path'], '/');// 默认的路径
$options['method'] = $server['REQUEST_METHOD'];// 方法
$options['domain'] = $info['scheme'] . '://' . $server['HTTP_HOST'];// 计划端口号
$options['content'] = $content;// 内容
self::$instance = new self($options);// 实例化 自己
return self::$instance;// 返回自己
}

/**
* 获取当前包含协议的域名
* @access public
* @param string $domain 域名
* @return string
*/
public function domain($domain = null)
{// 获取当前包含协议的域名
if (!is_null($domain)) {// 如果域名不为空
$this->domain = $domain;
return $this;
} elseif (!$this->domain) {
$this->domain = $this->scheme() . '://' . $this->host();
}
return $this->domain;
}// 设置 + 获取,设置 就返回对象 获取 就获取当前的域名

/**
* 获取当前完整URL 包括QUERY_STRING
* @access public
* @param string|true $url URL地址 true 带域名获取
* @return string
*/
public function url($url = null)// 设置 与 获取 创造 与 毁灭
{
if (!is_null($url) && true !== $url) {
$this->url = $url;
return $this;
} elseif (!$this->url) {// 默认为空
if (IS_CLI) {// 如果是命令行的方式 获取的参数 为 不过应该很少用
$this->url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
} elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) {// 如果重写
$this->url = $_SERVER['HTTP_X_REWRITE_URL'];
} elseif (isset($_SERVER['REQUEST_URI'])) {// 如果存在
$this->url = $_SERVER['REQUEST_URI'];
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) {// 如果是 pathinfo 方式
$this->url = $_SERVER['ORIG_PATH_INFO'] . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '');
} else {
$this->url = '';// 如果系统没有,就是空
}
}
return true === $url ? $this->domain() . $this->url : $this->url;// 拼接 带有域名的,或者 不带有域名的
}