构建自己的PHP框架--创建组件的机制
在之前的博客中,我们完成了基本的Model类,但是大家应该还记得,我们创建数据库的pdo实例时,是hard好的配置,并且直接hard在Model类中。
代码如下:
public static function getDb()
{
if (empty(static::$pdo)) {
$host = 'localhost';
$database = 'sf';
$username = 'jun';
$password = 'jun';
$options = [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false
];
static::$pdo = new PDO("mysql:host=$host;dbname=$database", $username, $password, $options);
static::$pdo->exec("set names 'utf8'");
}
return static::$pdo;
}
这明显是不合适的,修改的时候需要取修改框架的代码。现在我们就来将它抽出来。
首先我们需要将配置拿到相应的配置文件中,我们在simple-framework文件夹下创建一个config文件夹,然后添加一个db.php文件。在里面添加相关的配置。
代码如下:
return [
'class' => '\PDO',
'dsn' => 'mysql:host=localhost;dbname=sf',
'username' => 'jun',
'password' => 'jun',
'options' => [
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_STRINGIFY_FETCHES => false,
],
];
其实就是返回一个数组,数组中是我们创建pdo实例所需要的参数。在创建pdo实例之前,将db.php文件require进来即可。
代码如下:
public static function getDb()
{
if (empty(static::$pdo)) {
$config = require('../config/db.php');
static::$pdo = new $config['class']($config['dsn'], $config['username'], $config['password'], $config['options']);
static::$pdo->exec("set names 'utf8'");
}
return static::$pdo;
}
这样还是有点不爽,在require配置文件的时候,我需要一层层的去看相对位置,如果错了,就找不到了。而且将来不管是配置文件还是Model文件的位置变动了,相对位置就变了,我都需要修改这段代码。如果改成绝对地址是不是会好一些,至少配置文件位置不变,就不需要修改这段代码。
但是要改成绝对地址,我就需要定位simple-framework文件夹的地址,所以我们在public/index.php中define一个常量,标记simple-framework文件夹的地址。
public/index.php代码如下:
<?php
define('SF_PATH', dirname(__DIR__));
require_once(SF_PATH . '/vendor/autoload.php');
$application = new sf\web\Application();
$application->run();
定义了常量SF_PATH,Model中的require可改为如下代码:
$config = require(SF_PATH . '/config/db.php');
OK,这样看起来好多了。
但是我又想到,假设将来我又需要一个cache的实例,我是不是又要把getDb的方法写一遍呢?如果要避免这种情况,我是不是应该把它抽想出来呢?那要如何抽象呢?
这个时候我们可能需要有一个方法,我们只需要告诉它我们需要创建一个什么实例,然后它就自己去取相应的参数,并创建出相应的实例来。这样是不是很爽。
我们需要在src文件夹下创建一个Sf.php,在其中创建一个createObject方法,用来创建实例。
但这个时候我们又遇到一个问题,pdo实例创建的时候,要按一定的顺序传一定个数的参数,但我们之后需要创建的其它的实例,可能传递的参数的个数和key都不同,那我们该怎么办?
所以我们需要一种机制能够将参数存起来,真正创建实例时,再取出来使用。我们可以在src/db文件夹下创建一个Connection类,Sf中的createObject方法创建了这个类的实例,这个类提供一个创建pdo实例的方法即可。
Sf.php中的代码如下:
<?php
/**
* Sf is a helper class serving common framework functionalities.
* @author Harry Sun <sunguangjun@126.com>
*/
class Sf
{
/**
* Creates a new object using the given configuration.
* You may view this method as an enhanced version of the `new` operator.
* @param string $name the object name
*/
public static function createObject($name)
{
$config = require(SF_PATH . "/config/$name.php");
// create instance
$instance = new $config['class']();
unset($config['class']);
// add attributes
foreach ($config as $key => $value) {
$instance->$key = $value;
}
return $instance;
}
}
Sf类没有namespace,所以不符合psr4的规则,需要手动引入,在public/index.php中加入如下一句话:
require_once(SF_PATH . '/src/Sf.php');
Connection.php中的代码如下:
<?php
namespace sf\db;
use PDO;
/**
* Connection represents a connection to a database via [PDO](php.net/manual/en/book.pdo.php).
* @author Harry Sun <sunguangjun@126.com>
*/
class Connection
{
/**
* @var string the Data Source Name, or DSN, contains the information required to connect to the database.
* Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) on
* the format of the DSN string.
* @see charset
*/
public $dsn;
/**
* @var string the username for establishing DB connection. Defaults to `null` meaning no username to use.
*/
public $username;
/**
* @var string the password for establishing DB connection. Defaults to `null` meaning no password to use.
*/
public $password;
/**
* @var array PDO attributes (name => value)
* to establish a DB connection. Please refer to the
* [PHP manual](http://www.php.net/manual/en/function.PDO-setAttribute.php) for
* details about available attributes.
*/
public $attributes;
public function getDb()
{
return new PDO($this->dsn, $this->username, $this->password, $this->attributes);
}
}
虽然不显示声明dsn/username/password和attributes属性也是可行的,但我觉得还是声明出来比较好,这样大家看到这个类的时候,会知道有哪些属性。
Model类中的getDb方法改成如下代码:
public static function getDb()
{
if (empty(static::$pdo)) {
static::$pdo = Sf::createObject('db')->getDb();
static::$pdo->exec("set names 'utf8'");
}
return static::$pdo;
}
不要忘记需要use一下Sf。
config中的db.php也要跟着修改,代码如下:
<?php
return [
'class' => '\sf\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=sf',
'username' => 'jun',
'password' => 'jun',
'attributes' => [
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_STRINGIFY_FETCHES => false,
],
];
我默默的将options换成了attributes,毕竟在PDO的文档里,写的是attribute。
好了,今天就先到这里。项目内容和博客内容也都会放到Github上,欢迎大家提建议。
code:https://github.com/CraryPrimitiveMan/simple-framework/tree/0.8
blog project:https://github.com/CraryPrimitiveMan/create-your-own-php-framework
构建自己的PHP框架--创建组件的机制的更多相关文章
- 基于Vue的Quasar Framework 介绍 这个框架UI组件很全面
基于Vue的Quasar Framework 介绍 这个框架UI组件很全面 基于Vue的Quasar Framework 中文网http://www.quasarchs.com/ quasarfram ...
- net 和Mono 构建的HTTP服务框架
Nancy是一个基于.net 和Mono 构建的HTTP服务框架,是一个非常轻量级的web框架. 设计用于处理 DELETE, GET, HEAD, OPTIONS, POST, PUT 和 PATC ...
- IDE 、SDK 、API区别、库、框架、组件、CLI
IDE:集成开发环境:包括代码编辑器.代码检测.代码调试器.译器/解释器.以及其他工具 SDK:SDK是IDE的基础引擎 ,比IDE更基本,因为它通常没有图形工具.工程师为辅助开发某类软件的相关文档. ...
- 跟着刚哥学习Spring框架--创建HelloWorld项目(一)
1.Spring框架简介 Spring是一个开源框架,Spring是在2003年兴起的一个轻量级的开源框架,由Rod johnson创建.主要对JavaBean的生命周期进行管理的轻量级框架,Spri ...
- Angular动态创建组件之Portals
这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Por ...
- react创建组件的几种方式及其区别
react创建组件有如下几种方式 ①.函数式定义的无状态组件 ②.es5原生方式React.createClass定义的组件 ③.es6形式的extends React.Component定义的组 ...
- PHP yii框架FormWidget组件
本篇文章介绍的是PHP yii框架Form组件,方便在view层更好调用此功能,话不多说上代码:1.先继承yii本身Widget类 <?php/** * User: lsh */ namespa ...
- React创建组件的三种方式及其区别
内容转载于http://www.cnblogs.com/wonyun/p/5930333.html React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: ...
- 以jar包的形式来使用前端的各种框架、组件。
springboot(二):web综合开发 - 纯洁的微笑博客 http://www.ityouknow.com/springboot/2016/02/03/spring-boot-web.html ...
随机推荐
- 优化curl并发使用
经典curl并发的处理流程:首先将所有的URL压入并发队列, 然后执行并发过程, 等待所有请求接收完之后进行数据的解析等后续处理. 在实际的处理过程中, 受网络传输的影响, 部分URL的内容会优先于其 ...
- Android 怎么退出整个应用程序?
方法一: 我们在写android应用程序时,经常会遇到想退出当前Acitivity,或者直接退出应用程序.我之前的一般操作是按返回键,或者直接按home键直接返回,其实这两种操作都没有关闭当前应用程序 ...
- can't connect to mysql server on 'localhost'(10061)
在linux下安装Navicat,想说在windows下试一试phpmyadmin之外的mysql图形工具. 显示下载安装了mysql workbench,链接成功.然后又弄了一下输入法重启,想说试一 ...
- Spark优化之二:集群上运行jar程序,状态一直Accepted且不停止不报错
如果运行Spark集群时状态一直为Accepted且不停止不报错,比如像下面这样的情况: 15/06/14 11:33:33 INFO yarn.Client: Application report ...
- 如何用js得到当前页面的url信息方法(JS获取当前网址信息)
设置或获取对象指定的文件名或路径. alert(window.location.pathname) 设置或获取整个 URL 为字符串. alert(window.location.href); 设置或 ...
- mysql自动加入添加时间列
`addtime` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- linux下打包zip文件
zip [参数] [打包后的文件名] [打包的目录路径] linux zip命令参数列表:-a 将文件转成ASCII模式-F 尝试修复损坏的压缩文件 -h 显示帮助界面-m 将文件压 ...
- SQL Server恢复软件SysTools SQL Recovery/SysTools SQL Server Recovery Manager
SQL Server恢复软件SysTools SQL Recovery/SysTools SQL Server Recovery Manager http://www.systoolsgroup.co ...
- 解读ASP.NET 5 & MVC6系列
本系列的大部分内容来自于微软源码的阅读和网络,大部分测试代码都是基于VS RC版本进行测试的. 解读ASP.NET 5 & MVC6系列(1):ASP.NET 5简介 解读ASP.NET 5 ...
- 分享我们项目中基于EF事务机制的架构
写在前面: 1. 本文中单元测试用到的数据库,在执行测试之前,会被清空,即使用空数据库. 2. 本文中的单元测试都是正确通过的. 要理解EF的事务机制,首先要理解这2个类:TransactionSco ...