项目配置需要在入口文件传递给SinglePHP,目前支持的配置如下:

$config = array(
    'APP_PATH'    => './App/',       #APP业务代码文件夹
    'DB_HOST'     => '127.0.0.1',    #数据库主机地址
    'DB_PORT'     => '3306',         #数据库端口,默认为3306
    'DB_USER'     => 'root',         #数据库用户名
    'DB_PWD'      => 'toor',         #数据库密码
    'DB_NAME'     => 'singlephp',    #数据库名
    'DB_CHARSET'  => 'utf8',         #数据库编码,默认utf8
    'PATH_MOD'    => 'NORMAL',       #路由方式,支持NORMAL和PATHINFO,默认NORMAL
    'USE_SESSION' => true,           #是否开启session,默认false
);
SinglePHP::getInstance($config)->run();
              

目前路由支持NORMAL和PATHINFO两种方式

NORMAL方式

在NORMAL方式下,必须通过url的c和a参数来指定对应的controller和action,默认都是Index。url的路由关系示例:

index.php                //IndexController->IndexAction
index.php?a=Test         //IndexController->TestAction
index.php?c=Test         //TestController->IndexAction
index.php?c=Test&a=Test  //TestController->TestAction

PATHINFO方式

PATHINFO方式需要webserver支持PATHINFO,可以通过var_dump($_SERVER['PATH_INFO']);来查看。如果webserver不支持PATHINFO,而又配置成了PATHINFO方式的路由,SinglePHP将会忽略此项配置而采用NORMAL方式路由。示例如下:

index.php            //IndexController->IndexAction
index.php/Test       //TestController->IndexAction
index.php/Test/Test  //TestController->TestAction

同时可以配合webserver的rewrite功能将index.php去掉,美化url。

所有的控制器必须继承Controller类或其子类,并且类名必须以Controller结尾,统一放置在Controller目录下,文件名必须是“类名.class.php”。

每一个Action对应控制器类的一个方法,方法名必须以Action结尾,同时必须是public权限。

示例代码如下:

<?php
class IndexController extends Controller {  //控制器必须继承Controller类或其子类
    public function IndexAction(){          //public权限,方法名以Action结尾
    }
    public function other(){                //方法名不是以Action结尾,不可以被直接路由到
    }
}

同时控制器提供了几个方法用来简化操作:

<?php
class IndexController extends Controller { 
    public function RedirectAction(){ 
        $this->redirect('http://www.baidu.com'); //302跳转到百度
    }
    public function AjaxAction(){
        $ret = array(
            'result' => true,
            'data'   => 123,
        );
        $this->AjaxReturn($ret);                //将$ret格式化为json字符串后输出到浏览器
    }
}

SinglePHP不能称为一个MVC框架的原因就是SinglePHP没有M。为了精简代码,SinglePHP只提供了简单的queryexecute,并没有做模型和数据表的映射。

可以通过M函数来便捷的获取数据库对象(没错就是抄的thinkphp你咬我啊)。代码如下:

<?php
$db = M();  //获取数据库对象,前提是在入口文件配好数据库相关的配置
$name = $db->escape($_GET['name']);  //转义字符
//查询,失败返回false,否则返回数据
$ret = $db->query("select * from user where name = '$name'");
echo $db->getRows();  //获得返回的行数
echo $db->getLastSql();  //获得上一次执行的sql
//执行增删改语句,失败返回false,否则返回影响的行数
$count = $db->execute("insert user (name, email) values ('leo108', 'leo108@qq.com')");
echo $db->getRows();  //获得返回的行数
echo $db->getInsertId();  //获得自增ID
echo $db->getError();  //如果执行sql失败,可以获得失败原因

SinglePHP没有提供语法花哨的模板引擎,而是采用原生的PHP语法。一来降低学习成本,二来减少SinglePHP的体积。

通过Controller类的assign来给模板变量赋值,通过display方法来渲染模板。

assign方法接受两个参数,第一个参数是模板变量名,第二个参数是模板变量值。

display方法可以接受1个或0个参数。当没有参数时,则默认使用View/控制器名/Action名.php作为模板;如果参数值不带有'/',则默认使用View/控制器名/参数值.php作为模板;如果参数值带有1个'/',则会使用View/参数值.php作为模板。

示例代码如下:

<?php
class IndexController extends Controller { 
    public function IndexAction(){
        $this->assign('str', 'hello world'); //给模板变量str赋值'hello world'
        $this->display();           //使用View/Index/Index.php作为模板
    }
    public function TestAction(){
        $this->display('test2');    //使用View/Index/test2.php作为模板
    }
    public function AnotherTestAction(){
        $this->display('user/test');    //使用View/user/test.php作为模板
    }
}

SinglePHP还提供了模板include功能,通过View::tplInclude来引入其他模板,该静态方法接受1个或2个参数,第一个参数是模板,规则与display的参数相同,第二个参数是传递给该模板的模板变量,必须是关联型数组。

示例代码如下:

View/Public/header.php 公共头部文件

<!DOCTYPE html>
<head>
    <title><?php echo $title;?></title>
</head>

View/Index/Index.php 首页模板文件

<?php
$data = array(
        'title' => 'Welcome',  //设置title变量为Welcome
        );
View::tplInclude('Public/header', $data); ?>
xxxxxxx其他玩意

Widget功能可以说是SinglePHP简单模板引擎的一个补充,坚持简单而强大的原则~

每个Widget都需要继承Widget类,类名必须以Widget结尾,放在App/Widget目录下,文件名必须是"类名.class.php"。Widget的模板文件在Widget/Tpl文件下。代码如下:

Widget/SideWidget.class.php

<?php
class SideWidget extends Widget{
    public function invoke($data){   //必须重写invoke方法
        //对$data做一些处理
        $this->assign('data', $data);  //给widget模板变量赋值,与控制器的assign相同
        $this->display();              //渲染widget模板,本例使用的模板是Widget/Tpl/SideWidget.php,如果传入参数,则使用Widget/Tpl/参数.php
    }
}

View/Index/Index.php 可以是任意模板文件

<?php
W('Side', array('page' => 'Index'));    //在模板文件中通过W函数来调用Widget,第二个参数会传递给invoke方法

Tip:什么时候用View::tplInclude?什么时候用Widget

既然View::tplInclude也可以传递模板变量,那为何还需要Widget功能呢?

开发Widget功能主要是考虑到让视图文件更专注于展示,避免将业务逻辑写在模板文件中。当传递的数据需要进一步处理之后再展示出来,就需要用Widget而不是View::tplInclude。当然如果你能忍受在模板文件中写业务逻辑,也可以不用Widget(羽量级的网站没有那么多的破规范:))

除了自动加载Controller类和Widget类之外,SinglePHP还会自动加载一个App/common.php和App/Lib下的类文件

App/common.php这个文件里可以是通用的函数,如果不存在也不会影响程序的运行。

当SinglePHP遇到一个未定义的类时,会尝试去加载App/Lib/类名.class.php,例如有一个分页类Page,那么会尝试加载App/Lib/Page.class.php,如果文件不存在,或者文件中也没有定义这个类,将会报错~

SinglePHP提供了一个简单的日志类,可以分级记录各类信息,目前提供了Fatal、Warning、Notice、Debug和Sql5种级别。日志会存储在App/Log目录下,当然前提条件是该目录是可写的。日志是按天存储的,如果是Fatal和Warning的日志,则会存放在.log.wf文件里。SinglePHP本身会打一些必要的日志,例如sql执行记录,路由出错等等。

代码如下:

<?php
Log::fatal('something');
Log::warn('something');
Log::notice('something');
Log::debug('something');
Log::sql('something');