首页 >后端开发 >php教程 >构建自各儿的PHP框架-创建组件的机制

构建自各儿的PHP框架-创建组件的机制

WBOY
WBOY原创
2016-06-13 12:29:03849浏览

构建自己的PHP框架--创建组件的机制

在之前的博客中,我们完成了基本的Model类,但是大家应该还记得,我们创建数据库的pdo实例时,是hard好的配置,并且直接hard在Model类中。

代码如下:

<code class="sourceCode php">    <span class="kw">public</span> <span class="kw">static</span> <span class="kw">function</span> getDb<span class="ot">()</span>    {        <span class="kw">if</span> <span class="ot">(</span><span class="fu">empty</span><span class="ot">(</span><span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">))</span> {            <span class="kw">$host</span> = <span class="st">&#39;localhost&#39;</span><span class="ot">;</span>            <span class="kw">$database</span> = <span class="st">&#39;sf&#39;</span><span class="ot">;</span>            <span class="kw">$username</span> = <span class="st">&#39;jun&#39;</span><span class="ot">;</span>            <span class="kw">$password</span> = <span class="st">&#39;jun&#39;</span><span class="ot">;</span>            <span class="kw">$options</span> = <span class="ot">[</span>                <span class="kw">PDO</span>::<span class="kw">ATTR_EMULATE_PREPARES</span> => <span class="kw">false</span><span class="ot">,</span>                <span class="kw">PDO</span>::<span class="kw">ATTR_STRINGIFY_FETCHES</span> => <span class="kw">false</span>            <span class="ot">];</span>            <span class="kw">static</span>::<span class="kw">$pdo</span> = <span class="kw">new</span> <span class="kw">PDO</span><span class="ot">(</span><span class="st">"mysql:host=</span><span class="kw">$host</span><span class="st">;dbname=</span><span class="kw">$database</span><span class="st">"</span><span class="ot">,</span> <span class="kw">$username</span><span class="ot">,</span> <span class="kw">$password</span><span class="ot">,</span> <span class="kw">$options</span><span class="ot">);</span>            <span class="kw">static</span>::<span class="kw">$pdo</span>-><span class="fu">exec</span><span class="ot">(</span><span class="st">"set names &#39;utf8&#39;"</span><span class="ot">);</span>        }        <span class="kw">return</span> <span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">;</span>    }</code>

这明显是不合适的,修改的时候需要取修改框架的代码。现在我们就来将它抽出来。

首先我们需要将配置拿到相应的配置文件中,我们在simple-framework文件夹下创建一个config文件夹,然后添加一个db.php文件。在里面添加相关的配置。

代码如下:

<code class="sourceCode php"><span class="kw">return</span> <span class="ot">[</span>    <span class="st">&#39;class&#39;</span> => <span class="st">&#39;\PDO&#39;</span><span class="ot">,</span>    <span class="st">&#39;dsn&#39;</span> => <span class="st">&#39;mysql:host=localhost;dbname=sf&#39;</span><span class="ot">,</span>    <span class="st">&#39;username&#39;</span> => <span class="st">&#39;jun&#39;</span><span class="ot">,</span>    <span class="st">&#39;password&#39;</span> => <span class="st">&#39;jun&#39;</span><span class="ot">,</span>    <span class="st">&#39;options&#39;</span> => <span class="ot">[</span>        \<span class="kw">PDO</span>::<span class="kw">ATTR_EMULATE_PREPARES</span> => <span class="kw">false</span><span class="ot">,</span>        \<span class="kw">PDO</span>::<span class="kw">ATTR_STRINGIFY_FETCHES</span> => <span class="kw">false</span><span class="ot">,</span>    <span class="ot">],</span><span class="ot">];</span></code>

其实就是返回一个数组,数组中是我们创建pdo实例所需要的参数。在创建pdo实例之前,将db.php文件require进来即可。

代码如下:

<code class="sourceCode php">    <span class="kw">public</span> <span class="kw">static</span> <span class="kw">function</span> getDb<span class="ot">()</span>    {        <span class="kw">if</span> <span class="ot">(</span><span class="fu">empty</span><span class="ot">(</span><span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">))</span> {            <span class="kw">$config</span> = <span class="kw">require</span><span class="ot">(</span><span class="st">&#39;../config/db.php&#39;</span><span class="ot">);</span>            <span class="kw">static</span>::<span class="kw">$pdo</span> = <span class="kw">new</span> <span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;class&#39;</span><span class="ot">](</span><span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;dsn&#39;</span><span class="ot">],</span> <span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;username&#39;</span><span class="ot">],</span> <span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;password&#39;</span><span class="ot">],</span> <span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;options&#39;</span><span class="ot">]);</span>            <span class="kw">static</span>::<span class="kw">$pdo</span>-><span class="fu">exec</span><span class="ot">(</span><span class="st">"set names &#39;utf8&#39;"</span><span class="ot">);</span>        }        <span class="kw">return</span> <span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">;</span>    }</code>

这样还是有点不爽,在require配置文件的时候,我需要一层层的去看相对位置,如果错了,就找不到了。而且将来不管是配置文件还是Model文件的位置变动了,相对位置就变了,我都需要修改这段代码。如果改成绝对地址是不是会好一些,至少配置文件位置不变,就不需要修改这段代码。

但是要改成绝对地址,我就需要定位simple-framework文件夹的地址,所以我们在public/index.php中define一个常量,标记simple-framework文件夹的地址。

public/index.php代码如下:

<code class="sourceCode php"><span class="kw"><?php</span><span class="fu">define</span><span class="ot">(</span><span class="st">&#39;SF_PATH&#39;</span><span class="ot">,</span> <span class="fu">dirname</span><span class="ot">(</span><span class="kw">__DIR__</span><span class="ot">));</span><span class="kw">require_once</span><span class="ot">(</span><span class="kw">SF_PATH</span> . <span class="st">&#39;/vendor/autoload.php&#39;</span><span class="ot">);</span><span class="kw">$application</span> = <span class="kw">new</span> sf\web\Application<span class="ot">();</span><span class="kw">$application</span>->run<span class="ot">();</span></code>

定义了常量SF_PATH,Model中的require可改为如下代码:

<code class="sourceCode php"><span class="kw">$config</span> = <span class="kw">require</span><span class="ot">(</span><span class="kw">SF_PATH</span> . <span class="st">&#39;/config/db.php&#39;</span><span class="ot">);</span></code>

OK,这样看起来好多了。

但是我又想到,假设将来我又需要一个cache的实例,我是不是又要把getDb的方法写一遍呢?如果要避免这种情况,我是不是应该把它抽想出来呢?那要如何抽象呢?

这个时候我们可能需要有一个方法,我们只需要告诉它我们需要创建一个什么实例,然后它就自己去取相应的参数,并创建出相应的实例来。这样是不是很爽。

我们需要在src文件夹下创建一个Sf.php,在其中创建一个createObject方法,用来创建实例。

但这个时候我们又遇到一个问题,pdo实例创建的时候,要按一定的顺序传一定个数的参数,但我们之后需要创建的其它的实例,可能传递的参数的个数和key都不同,那我们该怎么办?

所以我们需要一种机制能够将参数存起来,真正创建实例时,再取出来使用。我们可以在src/db文件夹下创建一个Connection类,Sf中的createObject方法创建了这个类的实例,这个类提供一个创建pdo实例的方法即可。

Sf.php中的代码如下:

<code class="sourceCode php"><span class="kw"><?php</span><span class="co">/**</span><span class="co"> * Sf is a helper class serving common framework functionalities.</span><span class="co"> * </span><span class="kw">@author</span><span class="co"> Harry Sun </span><span class="kw"><sunguangjun</span><span class="ot">@126.com</span><span class="kw">></span><span class="co"> */</span><span class="kw">class</span> Sf{    <span class="co">/**</span><span class="co">     * Creates a new object using the given configuration.</span><span class="co">     * You may view this method as an enhanced version of the `new` operator.</span><span class="co">     * </span><span class="kw">@param</span><span class="co"> </span><span class="kw">string</span><span class="co"> $name the object name</span><span class="co">     */</span>    <span class="kw">public</span> <span class="kw">static</span> <span class="kw">function</span> createObject<span class="ot">(</span><span class="kw">$name</span><span class="ot">)</span>    {        <span class="kw">$config</span> = <span class="kw">require</span><span class="ot">(</span><span class="kw">SF_PATH</span> . <span class="st">"/config/</span><span class="kw">$name</span><span class="st">.php"</span><span class="ot">);</span>        <span class="co">// create instance</span>        <span class="kw">$instance</span> = <span class="kw">new</span> <span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;class&#39;</span><span class="ot">]();</span>        <span class="fu">unset</span><span class="ot">(</span><span class="kw">$config</span><span class="ot">[</span><span class="st">&#39;class&#39;</span><span class="ot">]);</span>        <span class="co">// add attributes</span>        <span class="kw">foreach</span> <span class="ot">(</span><span class="kw">$config</span> <span class="kw">as</span> <span class="kw">$key</span> => <span class="kw">$value</span><span class="ot">)</span> {            <span class="kw">$instance</span>-><span class="kw">$key</span> = <span class="kw">$value</span><span class="ot">;</span>        }        <span class="kw">return</span> <span class="kw">$instance</span><span class="ot">;</span>    }}</code>

Sf类没有namespace,所以不符合psr4的规则,需要手动引入,在public/index.php中加入如下一句话:

<code class="sourceCode php"><span class="kw">require_once</span><span class="ot">(</span><span class="kw">SF_PATH</span> . <span class="st">&#39;/src/Sf.php&#39;</span><span class="ot">);</span></code>

Connection.php中的代码如下:

<code class="sourceCode php"><span class="kw"><?php</span><span class="kw">namespace</span> sf\db<span class="ot">;</span><span class="kw">use</span> <span class="kw">PDO</span><span class="ot">;</span><span class="co">/**</span><span class="co"> * Connection represents a connection to a database via [PDO](php.net/manual/en/book.pdo.php).</span><span class="co"> * </span><span class="kw">@author</span><span class="co"> Harry Sun </span><span class="kw"><sunguangjun</span><span class="ot">@126.com</span><span class="kw">></span><span class="co"> */</span><span class="kw">class</span> Connection{    <span class="co">/**</span><span class="co">     * </span><span class="kw">@var</span><span class="co"> </span><span class="st">string</span><span class="co"> </span><span class="st">the</span><span class="co"> </span><span class="st">Data</span><span class="co"> </span><span class="st">Source</span><span class="co"> </span><span class="st">Name,</span><span class="co"> </span><span class="st">or</span><span class="co"> </span><span class="st">DSN,</span><span class="co"> </span><span class="st">contains</span><span class="co"> </span><span class="st">the</span><span class="co"> </span><span class="st">information</span><span class="co"> </span><span class="st">required</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">connect</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">the</span><span class="co"> </span><span class="st">database.</span><span class="co">     * Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) on</span><span class="co">     * the format of the DSN string.</span><span class="co">     * </span><span class="kw">@see</span><span class="co"> charset</span><span class="co">     */</span>    <span class="kw">public</span> <span class="kw">$dsn</span><span class="ot">;</span>    <span class="co">/**</span><span class="co">     * </span><span class="kw">@var</span><span class="co"> </span><span class="st">string</span><span class="co"> </span><span class="st">the</span><span class="co"> </span><span class="st">username</span><span class="co"> </span><span class="st">for</span><span class="co"> </span><span class="st">establishing</span><span class="co"> </span><span class="st">DB</span><span class="co"> </span><span class="st">connection.</span><span class="co"> </span><span class="st">Defaults</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">`null`</span><span class="co"> </span><span class="st">meaning</span><span class="co"> </span><span class="st">no</span><span class="co"> </span><span class="st">username</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">use.</span><span class="co">     */</span>    <span class="kw">public</span> <span class="kw">$username</span><span class="ot">;</span>    <span class="co">/**</span><span class="co">     * </span><span class="kw">@var</span><span class="co"> </span><span class="st">string</span><span class="co"> </span><span class="st">the</span><span class="co"> </span><span class="st">password</span><span class="co"> </span><span class="st">for</span><span class="co"> </span><span class="st">establishing</span><span class="co"> </span><span class="st">DB</span><span class="co"> </span><span class="st">connection.</span><span class="co"> </span><span class="st">Defaults</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">`null`</span><span class="co"> </span><span class="st">meaning</span><span class="co"> </span><span class="st">no</span><span class="co"> </span><span class="st">password</span><span class="co"> </span><span class="st">to</span><span class="co"> </span><span class="st">use.</span><span class="co">     */</span>    <span class="kw">public</span> <span class="kw">$password</span><span class="ot">;</span>    <span class="co">/**</span><span class="co">     * </span><span class="kw">@var</span><span class="co"> </span><span class="st">array</span><span class="co"> </span><span class="st">PDO</span><span class="co"> </span><span class="st">attributes</span><span class="co"> </span><span class="st">(name</span><span class="co"> </span><span class="st">=></span><span class="co"> </span><span class="st">value)</span><span class="co">     * to establish a DB connection. Please refer to the</span><span class="co">     * [PHP manual](http://www.php.net/manual/en/function.PDO-setAttribute.php) for</span><span class="co">     * details about available attributes.</span><span class="co">     */</span>    <span class="kw">public</span> <span class="kw">$attributes</span><span class="ot">;</span>    <span class="kw">public</span> <span class="kw">function</span> getDb<span class="ot">()</span>    {        <span class="kw">return</span> <span class="kw">new</span> <span class="kw">PDO</span><span class="ot">(</span><span class="kw">$this</span>->dsn<span class="ot">,</span> <span class="kw">$this</span>->username<span class="ot">,</span> <span class="kw">$this</span>->password<span class="ot">,</span> <span class="kw">$this</span>->attributes<span class="ot">);</span>    }}</code>

虽然不显示声明dsn/username/password和attributes属性也是可行的,但我觉得还是声明出来比较好,这样大家看到这个类的时候,会知道有哪些属性。

Model类中的getDb方法改成如下代码:

<code class="sourceCode php">    <span class="kw">public</span> <span class="kw">static</span> <span class="kw">function</span> getDb<span class="ot">()</span>    {        <span class="kw">if</span> <span class="ot">(</span><span class="fu">empty</span><span class="ot">(</span><span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">))</span> {            <span class="kw">static</span>::<span class="kw">$pdo</span> = Sf::createObject<span class="ot">(</span><span class="st">&#39;db&#39;</span><span class="ot">)</span>->getDb<span class="ot">();</span>            <span class="kw">static</span>::<span class="kw">$pdo</span>-><span class="fu">exec</span><span class="ot">(</span><span class="st">"set names &#39;utf8&#39;"</span><span class="ot">);</span>        }        <span class="kw">return</span> <span class="kw">static</span>::<span class="kw">$pdo</span><span class="ot">;</span>    }</code>

不要忘记需要use一下Sf。

config中的db.php也要跟着修改,代码如下:

<code class="sourceCode php"><span class="kw"><?php</span><span class="kw">return</span> <span class="ot">[</span>    <span class="st">&#39;class&#39;</span> => <span class="st">&#39;\sf\db\Connection&#39;</span><span class="ot">,</span>    <span class="st">&#39;dsn&#39;</span> => <span class="st">&#39;mysql:host=localhost;dbname=sf&#39;</span><span class="ot">,</span>    <span class="st">&#39;username&#39;</span> => <span class="st">&#39;jun&#39;</span><span class="ot">,</span>    <span class="st">&#39;password&#39;</span> => <span class="st">&#39;jun&#39;</span><span class="ot">,</span>    <span class="st">&#39;attributes&#39;</span> => <span class="ot">[</span>        \<span class="kw">PDO</span>::<span class="kw">ATTR_EMULATE_PREPARES</span> => <span class="kw">false</span><span class="ot">,</span>        \<span class="kw">PDO</span>::<span class="kw">ATTR_STRINGIFY_FETCHES</span> => <span class="kw">false</span><span class="ot">,</span>    <span class="ot">],</span><span class="ot">];</span></code>

我默默的将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

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn