gitbook 在线文档:
https://djunny.gitbooks.io/mzphp/content/index.html
enphp 在线加密:
[2016.12.30] 新增:
修复:
优化:
[2016.1.27]
新增:
修复:
优化:
既然大家都对性能这么有疑问,那么我拿 Hello World 来做一个简单的评测:
如何评测性能?
XDEBUG 后能产生一个 profile 通过 wincachegrind 能直观看到框架每一行的性能损耗。
测试环境
Windows 虚拟机,i7 2核 + 1G内存。PHP 最基础环境。
测试框架
测试结果
为了最佳性能,会让三个框架连续运行 20 次,然后输出 XDEBUG 的 profile:
最终的 profile 文件大小对比:
结果对比
mzphp 的 profile line-by-line结果:
TP 的 profile line-by-line结果:
CI 的 profile line-by-line结果:
mzphp 的 profile overall结果:
TP 的 profile overall结果:
CI 的 profile overall结果:
mzphp 跑热后,项目加载以及页面运行的时间为 1.6ms
CI 跑热后,项目加载以及页面运行的时间为 2.7ms
而 TP 跑热后,页面运行时间为:5.5ms
具体的 profile 数据,大家可以下载自行查看(window 下使用 wincachegrind 查看):
传送地址:profile下载
很久以来,楼主开发站点无数,一直希望能有一个枚,日开数站的 PHP 框架出现。
PHP 开发框架 mzphp,拥有特点:
mzphp 做为一直追求高效、简单、快速开发的 PHP 框架,希望大家多多支持。
如果需要 php 在 cli (命令行) 下运行,而您的操作系统是 windows。
请在系统 -> 环境变量 -> PATH -> 添加你的 php.exe 所在路径
git clone git@git.oschina.net:mz/mzphp2.git
完后,可更新子项目例子:
git submodule update
假我们需要建立的项目名称为:hello_world
请在项目目录建立一个hello_world(与 mzphp 目录同级)
复制 tools 目录下的 create_project.php 到 hello_world 目录。
提供两种方法生成项目结构:
cd hello_world
php create_project.php
访问生成的 index.php,可看到 mzphp Framework 字样,即访问成功.
打开项目 conf/conf.{env}.php 可按照注释编辑对应的参数。
{env}代表运行环境,由 $_SERVER['ENV'] 来控制 (默认为 debug)。
在 nginx 中,您可以通过添加:
fastcgi_param ENV 'online';
来切换线上、线下环境。
附上一些小的参数修改
index.php 中,你可以直接设置 define('DEBUG', 1) 永久打开 debug
也可以修改 hello_world_debug 这个字符串来告之项目当 url 中包含该字符时,自动开启 debug。
debug 开启时,右下角将出现一个浮动的运行时间展示,点击开来可以看到具体页面运行的信息。
注意
mzphp 框架为了减少磁盘 I/O,提高加载性能,会在项目第一次运行时,
在项目 control 目录中建立一个 user_control.class.php
同时,在该文件中定义一个 user_control 继承 base_control
<?php
!defined('FRAMEWORK_PATH') && exit('Accesss Deined');
class user_control extends base_control {
public function on_index(){
// define user
$user = 'djunny';
// assign variables
VI::assign('user', $user);
// default template path is view/user_index.htm
$this->show();
}
}
$this->show 调用显示模板,
可以自动识别为 view/user_index.htm,
即 {$control}_{$action}.htm
假如,view/user_index.htm 如下:
hello {$user}
使用 index.php?c=user-index 可访问到 user_control 的 on_index 方法,显示结果:
hello djunny
同时,使用命令行下:
php index.php user index
也能在命令行下看到同样的结果
小建议:
第一步:配置 conf 文件中的 db。
第二步:创建 user 表:
CREATE TABLE `user` (
`id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '',
PRIMARY KEY (`uid`)
) DEFAULT CHARSET=utf8 COMMENT='user'
第三步,model 层有二种调用方法。
第一种,不定义 model,直接使用
<?php
!defined('FRAMEWORK_PATH') && exit('Accesss Deined');
class user_control extends base_control {
public function on_index(){
// SELECT * FROM user WHERE id =1
$user = DB::T('user')->get(1);
// ...
}
}
此方法用于简单的 DAO 层调用。
第二种,在项目 model 目录中,新建一个 user.class.php 定义 user 继承自 base_model,
<?php
!defined('FRAMEWORK_PATH') && exit('Accesss Deined');
class user extends base_model {
function __construct() {
parent::__construct('user', 'id');
}
}
?>
在控制器中使用
<?php
!defined('FRAMEWORK_PATH') && exit('Accesss Deined');
class user_control extends base_control {
public function on_index(){
// SELECT * FROM user WHERE id =1
$user = $this->user->get(1);
// ...
}
}
mzphp 中,控制器会自动加载并初始化对应的 model 层。
另外:
// add table prefix
$table = DB::table('user');
// build SQL
$sql = sprintf("SELECT * FROM %s WHERE id=%d", $table, 1);
// get query and return first row
$first_row = DB::query($sql, 1);
// get query
$query = DB::query($sql);
while($val = DB::fetch($query)){
log::info($val);
}
// select method
// get first row from user where id =1
$user = DB::select('user', array('id'=>1), ' id ASC', 0);
// get all user array
$user_list = DB::select('user');
// get user count
$user_count = DB::select('user', 0, 0, -2);
模板中动态渲染内容,基本上由以上语法组成。
<!--{if 1==2}--><html></html><!--{/if}-->
<form {if 1==2}method="post"{/if}>
说明:
加载一个子模板。(子模板最多支持三层嵌套)
语法:
<!--{template header.htm}-->
说明:
if else 逻辑判断
语法:
<!--{if $a == $b && $b == 1}-->
a = b AND b = $b
<!--{elseif $b == 2 || $a == 3}-->
b = $b OR a = $a
<!--{elseif $a == 1}-->
a = 1
<!--{else}-->
a != 1
<!--{/if}-->
说明:
循环输出列表,可嵌套输出
语法:
<!--{loop $categories $index $cate}-->
categories[$index]= {$cate['name']}
<!--{/loop}-->
说明:
执行 php 代码。
语法:
<!--{eval
$a = 1;
$b = array(
'a' => 1,
'b' => 2,
);
}-->
<!--{eval echo $my_var;}-->
<!--{eval $my_arr = array(1, 2, 3);}-->
<!--{eval print_r($my_arr);}-->
<!--{eval exit();}-->
说明:
调用的方法并输出返回的内容。(方法必须以返回值)
语法:
{date('Y-m-d')}
{substr('123', 1)}
{print_r(array(1), 1)}
{spider::html2txt('<html></html>')}
语法:
<!--{static source_file target_file is_compress}-->
说明:
source_file 文件后缀为 scss 或者 js 时,会调用对应的编译类对文件进行编译和生成,生成的文件路径:static/{$target_file}
is_compress 参数可以为 0 或 1(默认 1),为 1 时,source_file 压缩,反之而不压缩。
在 debug 开启后,每次访问页面,都会生成一遍静态文件。在代码 push 的时候,需要产生的所有静态文件提交(线上不会再编译静态资源)
规范
静态文件寻找先后顺序
关于 css sprite
当 source_file 以 * 结尾时, 识别为 css sprite 模式,程序将会对 source_file 目录中的所有文件进行合并,读取所有图片的 size ,生成对应的 scss 文件和合并的 png 文件:
实例
<!--{static scss/png/* scss/sprite}-->
<!--{static scss/test.scss scss/_a.css}-->
<!--{static js/test1.js js/_a.js}-->
<!--{static js/test2.js js/_a.js 0}-->
<!--{static js/test3.js js/_a.js 1}-->
在以上例子中,系统做了以下处理:
1.先合并 scss/png/ 中所有图片为: scss/sprite.png,同时生成坐标 scss 文件:scss/sprite.scss
2.scss/test.scss 中调用 @import 'sprite'; 然后用 scss 语法来继承对应的 icon 或 图片即可,例(图片路径中.会变成-,更具体可以先成生一次后,打开生成后的sprite.scss看看):
.find{
@extend .loading-png;
}
3.开启合并文件 js/_a.js ,并将 js/test1.js 写入。
4.读取 js/test2.js,写入 js/_a.js 尾部。
5.读取 js/test3.js,并压缩,写入 js/_a.js
6. 替换成 空
7. 替换成 < link rel="stylesheet" href="scss/_a.css">
8. 替换成 < script src="js/_a.js"></ script>
9. 均替换成空
地址重写规则:
.htaccess
Options
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#control + action
RewriteRule ^(\w+)(?:[/\-_\|\.,])(\w+)(?:[/\-_\|\.,])(.*)$ index.php\?c=$1-$2&rewrite=$3 [L]
#control
RewriteRule ^(\w+)(?:[/\-_\|\.,])(.+)$ index.php\?c=$1&rewrite=$2 [L]
apache httpd.ini
[ISAPI_Rewrite]
RepeatLimit 32
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
#control + action
RewriteRule ^(\w+)(?:[/\-_\|\.,])(\w+)(?:[/\-_\|\.,])(.*)$ index.php\?c=$1-$2&rewrite=$3 [L]
#control
RewriteRule ^(\w+)(?:[/\-_\|\.,])(.+)$ index.php\?c=$1&rewrite=$2 [L]
nginx.conf
#control + action
rewrite ^(\w+)(?:[/\-_\|\.,])(\w+)(?:[/\-_\|\.,])(.*)$ index.php?c=$1-$2&rewrite=$3 last;
#control
rewrite ^(\w+)(?:[/\-_\|\.,])(.+)$ index.php?c=$1&rewrite=$2 last;
iis 7
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="mzphp_1" stopProcessing="true">
<match url="(\w+)(?:[/\-_\|\.,])(\w+)(?:[/\-_\|\.,])(.*)$" />
<action type="Rewrite" url="index.php?c={R:1}-{R:2}&rewrite={R:3}" appendQueryString="true" />
</rule>
<rule name="mzphp_2" stopProcessing="true">
<match url="(\w+)(?:[/\-_\|\.,])(.+)$" />
<action type="Rewrite" url="index.php?c={R:1}&rewrite={R:2}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
1.非地址重写链接:
index.php?c=control-action&var=...
2.系统地址重写(该地址中的 / 分隔符和 [.html] 均可在conf文件中配置):
/control/action/param1/param1value/param2/param2value...[.html]
conf/conf.[env].php 配置文件:
//url rewrite params
'rewrite_info' => array(
'comma' => '/', // options: / \ - _ | . ,
'ext' => '.html',// for example : .htm
),
使用系统地址重写时,您可以使用url方法,来生成url:
function url($control, $action, $params = array()) ;
例:
echo url('index', 'index', array('id'=>1));
echo url('index-index', array('id'=>1));
echo url('index-index', 'id=1&time=2015');
3.自定义地址重写:
index.php?c=control-action&rewrite=param1/param1value...
例如,我们需要使用:/help/123/ 来映射 index.php?c=article-help&id=123
可以在 urlrewrite 重写文件中配置(以 .htaccess 语法为例):
RewriteRule ^(help)/(\d+)/?$ index.php\?c=article-$1&rewrite=id/$2 [L]
注:本例中 rewrite 参数传入的分割符(/),视 rewrite_info 中的 comma 而定。
通过钩子方法,能在系统任何代码处调用在 hook 中注册的方法。
可用于插件或者扩展功能实现。
运行 hook
function hook($name) {}
输出 hook
输入 hook 一般在模板中直接调用比较多
function out_hook($returns, $implode = '') {}
在项目根目录的 index.php 中 ,定义存放钩子类的目录(例子中定义为项目根目录的 hook目录)
define('HOOK_PATH', ROOT_PATH.'hook/');
在对应目录下,创建一个 hook 目录 。
hook 目录下建立一个 hook_xxx.php,内容如下:
class hook_xxx {
static function func($abc = ''){
return '<a>';
}
}
TIP:hook_xxx.php 和 PHP 文件 class hook_xxx 必须一致。
此时,清理 tmp 目录(如果没有开启 DEBUG 模式则需要每次修改 hook 文件后操作)后,
在任意代码地方调用:
hook('func');
也支持参数传入:
hook('func', 'abc');
即调用对应 hook 到所有类包含的 func 静态方法。
TIP:并不是每个方法都会被 hook,记住,hook_xxx 类中带 _ (下划线)开头的静态方法是无法调用的。
TIP:同理,您可以将不想公开的方法用 _ (下划线)开头,防止 hook cache 到过多的方法,这样既可以优化 hook 扫描时的性能,又可以避免外部访问到。
hook 方法 返回结果类型为:Array
因为在 hook 目录中,存在的同样静态方法的类会有多个,调用时每个方法都会去调用一遍,所以会以数组形式返回。
循环输出或者在模板中可用
{out_hook(hook('func'), '<Br>')}
即可。
小技能
hook 可以按文件名顺序来排序,加排序的方法:
1.hook_xxx.php
2.hook_aaa.php
3.hook_ccc.php
数字越大,越优先加载,
TIP:插件排序,非特殊情况建议不要使用~
TIP: 如果调用 hook 途中,需要中止加载其它类的调用。
请在方法中返回:
return array(
// 通知 hook 系统不需要再运行其它 hook 类里的方法了
'HOOK' => HOOK_STOP,
// 返回的结果
'return' => 'xxxxx',
);
EnPHP 工具的路径:tools/enphp_project.php
EnPHP 是一款可以加密混淆 PHP 5-7 的工具,现内置于 mzphp Framework 中。 EnPHP 经多方测试已经支持加密混淆 99% 以上的 PHP 代码,欢迎测试反馈。
使用方法:
P.S. 重要的事情说三遍:备份!备份!备份!请在加密前备份好您的源码文件,通过 EnPHP 加密的文件均无法恢复!否则请不要使用。
P.S.S. 您也可以将 enphp 类与 spider 类拷出去单独使用。
enphp 在线加密地址:
更多实例敬请期待。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
Activity
Community
Health
Trend
Influence
:Code submit frequency
:React/respond to issue & PR etc.
:Well-balanced team members and collaboration
:Recent popularity of project
:Star counts, download counts etc.