当前位置: 首页 > news >正文

构建自己的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

相关文章:

  • 闲扯 『 document.write 』
  • 【vSphere故障案例】案例九:ESXi主机HA未配置错误
  • 在Mac上关于tomcat服务器的安装、配置、启动、部署web详细流程
  • git分享(二)git checkout
  • Android源码大放送之material design类型
  • 国内收益最高的聚合平台--KeyMob移动广告聚合平台
  • SQL 存储过程返回值
  • 利用excel办公软件快速拼凑sql语句
  • 如何利用又拍云玩转live photo,没有6S也能玩
  • PHP异常处理
  • Java之IO流总结
  • Java NIO系列教程(三) Buffer
  • 解决HP打印机错误:Couldn't open fifo
  • 第二章 策略模式
  • 又拍云,音视频CDN加速利器
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 0基础学习移动端适配
  • Django 博客开发教程 8 - 博客文章详情页
  • Druid 在有赞的实践
  • gops —— Go 程序诊断分析工具
  • JavaScript创建对象的四种方式
  • Js基础知识(一) - 变量
  • js如何打印object对象
  • PHP 小技巧
  • Sequelize 中文文档 v4 - Getting started - 入门
  • sessionStorage和localStorage
  • vue总结
  • 多线程 start 和 run 方法到底有什么区别?
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 在GitHub多个账号上使用不同的SSH的配置方法
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • 最简单的无缝轮播
  • Spring Batch JSON 支持
  • 继 XDL 之后,阿里妈妈开源大规模分布式图表征学习框架 Euler ...
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ( 10 )MySQL中的外键
  • (2020)Java后端开发----(面试题和笔试题)
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (pytorch进阶之路)扩散概率模型
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (南京观海微电子)——I3C协议介绍
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (原創) 如何將struct塞進vector? (C/C++) (STL)
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • **PHP二维数组遍历时同时赋值
  • .a文件和.so文件
  • .NET 药厂业务系统 CPU爆高分析
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .net6使用Sejil可视化日志
  • .NET的微型Web框架 Nancy
  • .NET牛人应该知道些什么(2):中级.NET开发人员
  • .NET正则基础之——正则委托