怎么从0到1创建一个PHP框架-2?

写在前面

本人开发的框架在2021年年初开发完成,后面没有再做过任何维护和修改。是仅供大家参考交流的学习项目,请勿使用在生产环境,也勿用作商业用途。

框架地址:
https://github.com/yijiebaiyi/fast_framework

实现缓存

框架中的缓存、日志、ORM都是使用适配器模式。即定义一个抽象类,抽象类中定义若干抽象方法。这样的话,继承了抽象类的方法必须要实现这些抽象方法。我们就可以通过统一的入口去根据配置去调用对应的适配器类了。

其中缓存适配了Redis、Memcache以及Memcached三种。开发者可以在config.php配置文件中自行配置。

缓存主要实现了将数据写入缓存和获取缓存数据两个方法,我们以redis为例,redis缓存主要是使用redis字符串存储结构,使用set和get方法来实现。

    public function get($key, &$time = null, &$expire = null){$_key = $this->makeKey($key);$res = $this->slaveObj->get($_key);if (is_null($res) || false === $res) {return null;}$res = unserialize($res);if ($res && isset($res['value'])) {$time = $res['time'];$expire = $res['expire'];return $res['value'];}return null;}public function set($key, $value = null, $expire = 3600): bool{return $this->masterObj->set($this->makeKey($key), serialize($this->makeValue($value, $expire)), $expire);}

前面的代码只是适配器的实现,那么我们怎么调用适配器类中的方法呢。我这边想到的是,在框架核心代码根目录创建一个缓存文件类,实现一个单例,通过配置来读取我们要使用什么类型的缓存(即使用哪个适配器类),配置中配置项是缓存适配器类的类名称,读取到了我们就加载他。具体实现代码:

    public static function instance($type = "default"): CacheDriver{if ($type === "default") {$_type = Config::get("Cache.default");} else {$_type = $type;}if (!$_type) {throw new Exception("The type can not be set to empty!");}if (!isset(self::$_instance[$_type])) {$conf = Config::get("Cache.{$_type}");if (empty($conf)) {throw new Exception("The '{$_type}' type cache config does not exists!");}$class = self::getNamespace() . "\\" . ucfirst($_type);$obj = new $class();if (!$obj instanceof CacheDriver) {throw new Exception("The '{$class}' not instanceof CacheDriver!");}$obj->init($conf);self::$_instance[$_type] = $obj;} else {$obj = self::$_instance[$_type];}return $obj;}

注:日志以及ORM的实现方法和缓存的实现类似,也是通过实现一个适配器,然后通过加载配置中定义的适配器类来加载。

实现完了之后我们测试一下:

设置:

        $cacheObj = Cache::instance('redis');$setRes = $cacheObj->setModuleName("user")->set(["id" => 1], ["name" => "ZhangSan"], 1000);if ($setRes) {echo "设置成功";} else {echo "设置失败";}

获取:

        $cacheObj = Cache::instance('redis');$res = $cacheObj->setModuleName("user")->get(["id" => 1], $time, $expire);var_dump($res, $time, $expire);

实现日志

日志的实现比较简单,主要值实现了日志的写入功能,通过php函数file_put_contents实现写入文件。当然也可以使用别的方法来实现。
相关代码:

public function write(string $message, string $type){if (empty($message)) {trigger_error('$message dose not empty! ');return false;}if (empty($type)) {trigger_error('$type dose not empty! ');return false;}$path = APP_PATH . DIRECTORY_SEPARATOR . 'runtime' . DIRECTORY_SEPARATOR . 'logs' . DIRECTORY_SEPARATOR . $type . '/' . date('Ym/d') . '.log';$mark = "\n\n===========================================================================\n";$mark .= 'time:' . date('Y/m/d H:i:s') . "\n";return \fast\util\File::write($mark . $message, $path, (FILE_APPEND | LOCK_EX));}
    public static function write($content, $path, $flags = 0){$path = trim($path);if (empty($path)) {trigger_error('$path must to be set!');return false;}$dir = dirname($path);if (!self::exists($dir)) {if (false == self::mkdir($dir)) {trigger_error('filesystem is not writable: ' . $dir);return false;}}$path = str_replace("//", "/", $path);return file_put_contents($path, $content, ((empty($flags)) ? (LOCK_EX) : $flags));}

应用层调用:

Log::write("这是一条info类型的log", Log::INFO);

实现操作数据库

数据库目前只实现了Mysql,如果需要支持别的数据库,只需要新增适配器即可。区别于缓存的实现,数据库使用接口interface作为适配器的约定。

mysql的实现主要依赖mysqli库,它对mysql库做了优化,防注入更完善一些。CURD的具体实现思路是,先获取要处理的数据,最终拼接成sql来执行。

注:链式调用通过方法返回$this来实现

简单看一下select查询的实现:

    public function select(){$this->checkMysqlOperate("table_empty");empty($this->_fields) && $this->_fields = "*";$sql = "SELECT {$this->_fields} FROM {$this->_table}";!empty($this->_where) && $sql .= " WHERE {$this->_where}";!empty($this->_order) && $sql .= " ORDER BY {$this->_order}";!empty($this->_group) && $sql .= " GROUP BY {$this->_group}";!empty($this->_limit) && $sql .= " LIMIT {$this->_offset}, {$this->_limit}";$this->_sql = $sql;$mysqliResult = mysqli_query($this->_connection, $this->_sql);if (false === $mysqliResult) {$this->_error = mysqli_error($this->_connection);return false;}return mysqli_fetch_all($mysqliResult, MYSQLI_ASSOC);}

我们在应用层调用一下select:

  $dbInstance = Db::getInstance();$result = $dbInstance->table('student')->where('SId in (01, 02, 13)')->order("SId DESC")->select();

update:

  $dbInstance = Db::getInstance();$dbInstance->table('student');$dbInstance->where(['Sid' => '01']);$result = $dbInstance->update($data);

数据验证器

数据验证器主要是用来验证数据是否符合我们的规范,可以用来验证表单数据,也可以用来验证业务数据。

主要实现是列举所有的验证规则依次校验,主要有这些规则校验:必传校验、类型校验、字符校验、数字校验、正则校验。

主要实现代码:

    public function check(array $data, array $rules): self{foreach ($rules as $rule => $message) {$dataRule = explode(".", $rule);if (count($dataRule) < 2) {continue;}// 必传校验if ($dataRule[1] == "required" && !isset($data[$dataRule[0]])) {array_push($this->errors, $message);continue;}if (!isset($data[$dataRule[0]])) {continue;}// 类型校验if (in_array($dataRule[1], $this->typeCheckName)) {if (false === self::typeCheck(strval($dataRule[1]), $data[$dataRule[0]])) {array_push($this->errors, $message);continue;}}// 字符校验if (in_array($dataRule[1], $this->stringCheckName) && isset($dataRule[2])) {if (false === self::stringCheck(strval($dataRule[1]), $dataRule[2], $data[$dataRule[0]])) {array_push($this->errors, $message);continue;}}// 数字校验if (in_array($dataRule[1], $this->operatorCheckName) && isset($dataRule[2])) {if (false === self::operatorCheck(strval($dataRule[1]), $dataRule[2], $data[$dataRule[0]])) {array_push($this->errors, $message);continue;}}// 正则校验if (in_array($dataRule[1], array_keys($this->pregCheckRules))) {if (false === self::pregCheck(strval($dataRule[1]), $data[$dataRule[0]])) {array_push($this->errors, $message);continue;}}}return $this;}

字符传校验部分代码:

    public function stringCheck(string $rule, $value, $dataValue): bool{$flag = true;switch ($rule) {case "max":strlen($dataValue) > $value && $flag = false;break;case "min":strlen($dataValue) < $value && $flag = false;break;case "length":strlen($dataValue) != $value && $flag = false;break;case "in":$value = explode(",", $value);!in_array($dataValue, $value) && $flag = false;break;case "notIn":$value = explode(",", $value);in_array($dataValue, $value) && $flag = false;break;}return $flag;}

业务层这样调用:

    public function testValidate(){$validate = new ValidateData();$data = ["age" => 17,"weight" => "50公斤","name" => "ZhangSan","country" => "这里是中国abc","sex" => "未知","mobile" => "11098186452",];$rules = ["age.required" => "请输入年龄","email.required" => "请输入邮箱","age.gt.18" => "年龄必须大于18","weight.float" => "体重必须为浮点数","name.max.6" => "姓名最大长度为6","country.alphaNum" => "国家必须为数字或者字母","sex.in.男,女" => "性别必须是男或者女","mobile.mobile" => "手机号码不合法",];$validate->check($data, $rules);var_dump($validate->getErrors());}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/63971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++--动态规划其他问题

1.一和零 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0…

springboot整合Excel填充数据

填充一组数据 准备模板 封装数据 import java.util.ArrayList; import java.util.List;/*** 使用实体类封装填充数据** 实体中成员变量名称需要和Excel表各种{}包裹的变量名匹配*/ Data public class FillData {private String name;private int age;// 生成多组数据代码pub…

在线问答和智能问答的区别在哪儿?如何搭建问答库?

在线问答和智能问答是两个不同的概念&#xff0c;虽然它们都是用来回答用户提出的问题&#xff0c;但在实现方式、功能和应用场景上有一些区别。 在线问答系统是一种基于互联网的问答服务&#xff0c;提供给用户一个平台&#xff0c;让他们可以提问问题并获取答案。在线问答系…

java八股文面试[数据库]——慢查询优化

分析慢查询日志 直接分析慢查询日志&#xff0c; mysql使用explain sql语句进行模拟优化器来执行分析。 oracle使用explain plan for sql语句进行模拟优化器来执行分析。 table | type | possible_keys | key |key_len | ref | rows | Extra EXPLAIN列的解释&#xff1a; ta…

【CSS】CSS 布局——定位

在CSS&#xff08;层叠样式表&#xff09;中&#xff0c;定位是一种用来控制元素在网页上的布局位置的技术。CSS提供了不同的定位属性&#xff0c;用于控制元素相对于其父元素或文档视口的位置。 CSS中常用的定位属性 静态定位&#xff08;static&#xff09;&#xff1a; 这是…

Mysql查询(SELECT)

基本查询&#xff1a;SELECT FROM SELECT 查询字段 FROM 表名; SELECT * FROM userinfo; 条件查询&#xff1a;用where表示查询条件 SELECT 查询字段 FROM 表名 WHERE 条件; 模糊查询&#xff1a;like %匹配0或多个字符&#xff0c;一般不用左模糊&#xff08;%放在左边&…

【电子取证篇】汽车取证检验标准

【电子取证篇】汽车取证检验标准 汽车取证鉴定可能涉及的测试/测量方法—【蘇小沐】 GA/T 976-2012《电子数据法庭科学鉴定通用方法》&#xff1b; GA/T 1998-2022《汽车车载电子数据提取技术规范》&#xff1b; GA/T 1999.2-2022《道路交通事故车辆速度鉴定方法 第2部分&…

windows使用-设置windows的远程访问用户数量

文章目录 前言相关操作总结前言 作为IT工程师,使用服务器做相应的软件操作时常有的事。最近一段时间,我们的团队多个成员都需要远程登录到一台windows2003Server的服务器处理相应的业务。而默认情况下,Windows系统只允许一名用户远程到服务器上,这给小伙伴的工作造成一些不…

时序预测 | MATLAB实现AR、ARMA、ARIMA时间序列预测模型答疑

时序预测 | MATLAB实现AR、ARMA、ARIMA时间序列预测模型答疑 目录 时序预测 | MATLAB实现AR、ARMA、ARIMA时间序列预测模型答疑基本介绍程序设计参考资料基本介绍 AR自回归模型(Autoregressive Model),通常简称为AR模型,是一种用于时间序列分析和预测的统计模型。它基于时间…

docker与phpstudy两种方式部署wordpress 并 开启伪静态

实际测试&#xff0c;可能是docker内存限制的缘故&#xff0c;docker部署的会比较卡 下载 wordpress phpstudy phpstudy中伪静态配置 伪静态 正常访问 WordPress 文章页的 URL 地址为 http://asa/index.php?p123。变成伪静态就是http://asa/123.html 。 伪静态是相对真实静…

Kubernetes技术--k8s核心技术Controller控制器

1.Controller概述 Controller是在集群上管理和运行容器的对象。是一个实际存在的对象。 2.pod和Controller之间的关系 pod通过controller实现应用的运维,包括伸缩、滚动升级等操作。 这里pod和controller通过label标签来建立关系。如下所示: 3.Deployment控制器应用场景 -1:…

MVCC简介、工作流程、优缺点

目录 简介 相关概念 工作流程 MVCC优缺点 简介 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;即多版本并发控制&#xff0c;是通过维护数据的历史版本&#xff0c;从而解决并发访问情况下的读一致性问题 相关概念 读锁&#xff1a; 也叫共享锁、S锁。若…

ubuntu 22.04 -- cmake安装

安装方式一&#xff1a;源码安装 1、下载安装包 官网下载&#xff1a;下载链接&#xff1a;https://cmake.org/download/ 也可以使用命令行下载 wget https://github.com/Kitware/CMake/releases/download/v3.26.5/cmake-3.26.5.tar.gz2、解压并安装 # 1、解压 tar -zxvf …

数据结构入门 — 队列

本文属于数据结构专栏文章&#xff0c;适合数据结构入门者学习&#xff0c;涵盖数据结构基础的知识和内容体系&#xff0c;文章在介绍数据结构时会配合上动图演示&#xff0c;方便初学者在学习数据结构时理解和学习&#xff0c;了解数据结构系列专栏点击下方链接。 博客主页&am…

Private market:借助ZK实现的任意计算的trustless交易

1. 引言 Private market&#xff0c;借助zk-SNARKs和以太坊来 隐私且trustlessly selling&#xff1a; 1&#xff09;以太坊地址的私钥&#xff08;ECDSA keypair&#xff09;2&#xff09;EdDSA签名3&#xff09;Groth16 proof&#xff1a;借助递归性来匿名交易Groth16 proo…

Pytest参数详解 — 基于命令行模式

1、--collect-only 查看在给定的配置下哪些测试用例会被执行 2、-k 使用表达式来指定希望运行的测试用例。如果测试名是唯一的或者多个测试名的前缀或者后缀相同&#xff0c;可以使用表达式来快速定位&#xff0c;例如&#xff1a; 命令行-k参数.png 3、-m 标记&#xff0…

Dubbo详解

1.1 Dubbo概述 Dubbo是阿里巴巴开源的基于 Java 的高性能RPC&#xff08;一种远程调用&#xff09; 分布式服务框架&#xff0c;致力于提供高性能和透明化的RPC远程服务调用方案&#xff0c;以及SOA服务治理方案。 每天为2千多个服务提供大于30亿次访问量支持&#xff0c;并被…

HDFS文件的读写流程

Hadoop HDFS的读写文件流程 HDFS写文件流程 客户端通过Distributed FileSystem模块向NameNode请求上传文件&#xff08;hadoop fs -put 文件名 文件路径 &#xff09; 判断该客户端是否有写入权限NameNode检查目标文件是否已存在&#xff0c;父目录是否存在。 NameNode返回是…

2、Spring6 入门

1、环境要求 JDK&#xff1a;Java17&#xff08;Spring6要求JDK最低版本是Java17&#xff09; Maven&#xff1a;3.6 Spring&#xff1a;6.0.2 2、构建模块 2.1 构建父模块spring6 点击“Create” 2.2 构建子模块spring-first 点击 Create 完成. 3、程序开发 3.1 引入依…

python面试题合集(一)

python技术面试题 1、Python中的幂运算 在python中幂运算是由两个 **星号运算的&#xff0c;实例如下&#xff1a; >>> a 2 ** 2 >>> a 4我们可以看到2的平方输出结果为4。 那么 ^指的是什么呢&#xff1f;我们用代码进行演示&#xff1a; >>>…