在之前的博客中,我们完成了基本的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框架--创建组件的机制的更多相关文章

  1. 基于Vue的Quasar Framework 介绍 这个框架UI组件很全面

    基于Vue的Quasar Framework 介绍 这个框架UI组件很全面 基于Vue的Quasar Framework 中文网http://www.quasarchs.com/ quasarfram ...

  2. net 和Mono 构建的HTTP服务框架

    Nancy是一个基于.net 和Mono 构建的HTTP服务框架,是一个非常轻量级的web框架. 设计用于处理 DELETE, GET, HEAD, OPTIONS, POST, PUT 和 PATC ...

  3. IDE 、SDK 、API区别、库、框架、组件、CLI

    IDE:集成开发环境:包括代码编辑器.代码检测.代码调试器.译器/解释器.以及其他工具 SDK:SDK是IDE的基础引擎 ,比IDE更基本,因为它通常没有图形工具.工程师为辅助开发某类软件的相关文档. ...

  4. 跟着刚哥学习Spring框架--创建HelloWorld项目(一)

    1.Spring框架简介 Spring是一个开源框架,Spring是在2003年兴起的一个轻量级的开源框架,由Rod johnson创建.主要对JavaBean的生命周期进行管理的轻量级框架,Spri ...

  5. Angular动态创建组件之Portals

    这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Por ...

  6. react创建组件的几种方式及其区别

    react创建组件有如下几种方式 ①.函数式定义的无状态组件 ②.es5原生方式React.createClass定义的组件   ③.es6形式的extends React.Component定义的组 ...

  7. PHP yii框架FormWidget组件

    本篇文章介绍的是PHP yii框架Form组件,方便在view层更好调用此功能,话不多说上代码:1.先继承yii本身Widget类 <?php/** * User: lsh */ namespa ...

  8. React创建组件的三种方式及其区别

    内容转载于http://www.cnblogs.com/wonyun/p/5930333.html React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: ...

  9. 以jar包的形式来使用前端的各种框架、组件。

    springboot(二):web综合开发 - 纯洁的微笑博客 http://www.ityouknow.com/springboot/2016/02/03/spring-boot-web.html ...

随机推荐

  1. Ubuntu创建桌面快捷方式

    默认情况下,ubuntu会将自动安装的软件快捷方式保存在/usr/share/applications目录下,如果我们要创建桌面快捷方式,只需要右键-复制-桌面 就Ok,如图: 上面的方法是通过系统自 ...

  2. druid sql黑名单 报异常 sql injection violation, part alway true condition not allow

    最近使用druid,发现阿里这个连接池 真的很好用,可以监控到连接池活跃连接数 开辟到多少个连接数 关闭了多少个,对于我在项目中查看错误 问题,很有帮助, 但是最近发现里面 有条sql语句 被拦截了, ...

  3. IIS 连接 oracle报Oracle.DataAccess版本错误解决办法

    通过IIS连接oracle时报“Could not load file or assembly 'Oracle.DataAccess, Version=2.112.3.0, Culture=neutr ...

  4. 解析文件+AcitonBar展示:

    //项目效果:

  5. 控制 Android 程序使用的内存

    如何控制应用程序使用的内存? 1. 记得关闭启动的服务 当服务中的任务完成后,要记得停止该服务.可以考虑使用 IntentService,因为 IntentService 在完成任务后会自动停止. 2 ...

  6. jsp和mysql乱码

    jsp页面,mysql页面上的中文不显示为乱码,各个地方使用的编码(如UTF-8,GB18030,GBK等)的编码保持一致即可. 1. jsp页面的编码: <%@page language=&q ...

  7. Spark优化之三:Kryo序列化

    Spark默认采用Java的序列化器,这里建议采用Kryo序列化提高性能.实测性能最高甚至提高一倍. Spark之所以不默认使用Kryo序列化,可能的原因是需要对类进行注册. Java程序中注册很简单 ...

  8. sqL编程篇(三) 游标与存储过程

    sql编程2 游标与存储过程 sql编程中的游标的使用:提供的一种对查询的结果集进行逐行处理的一种方式不用游标的处理解决方式:逐行修改工资update salar set 工资=‘新工资’ where ...

  9. shared_ptr

    省去对象指针的显示delete typedef tr1::shared_ptr<int> IntPtr; IntPtr fun() { IntPtr p = new int(3); ret ...

  10. 关于c++的 vector 容器的使用及创建方法

    1.vector向量容器的使用,vector具有自动管理的功能,可以进行元素的查找删除 创建方法: (1)  vector<int > v; 创建了一个v的容器,没指定容量: (2)  v ...