開發php框架入門
標簽: php
開發php框架入門
doopsPHP框架開發入門
倉庫地址
倉庫地址 https://gitee.com/gusijin/doopsPHP
為什么要自己開發框架呢?
- 發現比較好的設計用法
- 在看文檔的同時思考實現原理
- 自己實現,深刻理解
- 功能可以一點點實現
什么是MVC
MVC是一個架構,或者說是一個設計模式,它就是強制性使應用程序的輸入,處理和輸出分開。將一個應用程序分為三個部分:Model,View,Controller。
Model 模型(完成業務邏輯:由javaBean構成,在MVC的三個部件中,模型擁有最多的處理任務。例如它可能用象EJBs和javabean這樣的構件對象來處理數據庫。由于應用于模型的代碼只需寫一次就可以被多個視圖重用,所以減少了代碼的重復性。)
View 視圖(就是負責跟用戶交互的界面。一般就是由HTML,css元素組成的界面,當然現在還有一些像js,ajax,flex一些也都屬于視圖層。 在視圖層里沒有真正的處理發生,之負責數據輸出,并允許用戶操縱的方式。MVC能為應用程序處理很多不同的視圖。 )
Controller 控制器(接收請求—>調用模型—>根據結果派發頁面并經過模型處理返回相應數據 )
環境準備
- 最基本的PHP環境:
Nginx或者openresty
PHP5.4+ 及以上
MySQL5.6
目錄準備
在開發前,給這個框架先起個名字吧,叫:doopsPHP。
然后根據需要來把項目的目錄創建。
假設我們建立的項目為 project,目錄結構就這樣:
project WEB部署根目錄
├─app 應用目錄
│ ├─controller 控制器目錄
│ ├─model 模塊目錄
├─config 配置文件目錄
├─public 公共目錄
│ ├─themes 模板主題目錄
│ ├─index.php 入口文件
├─system 系統文件目錄
├─vendor 包管理目錄
├─env 參數配置文件
nginx配置
nginx.conf文件
配置要目錄到public
location / {
root /www/doopsPHP/public;
index index.php index.html index.htm;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
break;
}
}
location ~ \.php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /www/doopsPHP/public$fastcgi_script_name;
include fastcgi_params;
}
核心文件
入口文件
在 project 目錄public下新建 index.php 入口文件,文件內容為:
<?php
/**
* doopsPHP
* An open source application development framework for PHP
* Copyright (c) 2019 - 2020, gusijin
* @package doopsPHP
* @author gusijin
* @copyright Copyright (c) 2019 - 2020, gusijin
* @since Version 1.0.1
*/
if (version_compare(PHP_VERSION, '5.4.0', '<')) {
die('require PHP > 5.4.0');
};
define('PUBLIC_PATH', str_replace('\\', DIRECTORY_SEPARATOR, __DIR__) . DIRECTORY_SEPARATOR);
define("BASE_PATH", PUBLIC_PATH . '..' . DIRECTORY_SEPARATOR);
define("SYSTEM_PATH", BASE_PATH . 'system' . DIRECTORY_SEPARATOR);
define("APP_PATH", BASE_PATH . 'app' . DIRECTORY_SEPARATOR);
define("CONF_PATH", BASE_PATH . 'config' . DIRECTORY_SEPARATOR);
define("CORE_PATH", SYSTEM_PATH . 'core' . DIRECTORY_SEPARATOR);
require CORE_PATH . 'run.php';
配置文件
數據庫配置
env文件
···
DEBUG = true
DB_HOST = 127.0.0.1
DB_PORT = 3306
DB_USER = root
DB_PWD = 123456
DB_NAME = test
DB_CHATSET = utf8
···
自定義路由配置
config/routes.php
<?php
/**
* 自定義路由
* User: gusijin
* Date: 2019/6/25
* Time: 17:09
*/
return [
'ROUTES' => [
'shop.html' => ['action' => 'index/shop'],
],
];
實例化類
入口文件包含了run.php文件,
實例化,調用bootstrap()方法
system/core/run.php
<?php
namespace core;
//引入公共函數
require_once SYSTEM_PATH . 'common' . DIRECTORY_SEPARATOR . 'function.php';
//引入自動加載類,并注冊自動加載函數
require_once CORE_PATH . 'Loader.php';
//公共函數解析配置
spl_autoload_register('core\\Loader::autoLoad');
Router::bootstrap();
公共函數類
system/common/function.php
<?php
if (!function_exists('createUrl')) {
/**
* 獲取url
* @param string $info
* @return string
*/
function createUrl($info = '')
{
$url_info = explode(DIRECTORY_SEPARATOR, strtolower($info));
$controller = isset($url_info[1]) ? $url_info[0] : strtolower(CONTROLLER);
$action = isset($url_info[1]) ? $url_info[1] : $url_info[0];
if (isset($_GET['r'])) {
return DIRECTORY_SEPARATOR . 'index.php?r=' . $controller . DIRECTORY_SEPARATOR . $action;
} else {
return DIRECTORY_SEPARATOR . $controller . DIRECTORY_SEPARATOR . $action;
}
}
}
自動加載類
system/core/Loader.php
<?php
namespace core;
use Whoops;
class Loader
{
public static function autoLoad($class)
{
$vendorAutoloadFile = BASE_PATH . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
if (file_exists($vendorAutoloadFile)) {
include $vendorAutoloadFile;
}
$class = ltrim($class, '\\');
$class_path = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
if (file_exists(SYSTEM_PATH . $class_path)) {
include SYSTEM_PATH . $class_path;
//bug調試
if (Env::get('DEBUG')) {
$whoops = new Whoops\Run;
$whoops->pushHandler(new Whoops\Handler\PrettyPageHandler);
$whoops->register();
}
return true;
}
if (file_exists(APP_PATH . $class_path)) {
include APP_PATH . $class_path;
return true;
}
}
}
env配置類
system/core/Env.php
<?php
namespace core;
class Env
{
private static $env = null;
private static $envFile = 'env';
public static function reload()
{
$envFile = BASE_PATH . self::$envFile;
if (is_file($envFile)) {
self::$env = parse_ini_file($envFile, true);
} else {
echo 'env file is not exist';
exit();
}
}
/**
* 讀取env配置
* @param string $key
* @return string|null
*/
public static function get($key, $default = null)
{
if (is_null(self::$env)) {
self::reload();
}
return isset(self::$env[$key]) ? self::$env[$key] : $default;
}
}
路由解析類
system/core/Router.php
<?php
namespace core;
class Router
{
public static $uri;
protected static $contrallerName;
protected static $actionName;
/**
* 路由解析方法選擇
*/
public static function bootstrap()
{
self::setDebug();
self::$uri = $_SERVER['REQUEST_URI'];
if (isset($_GET['r'])) {
self::parseByCommonRouter();
} else {
self::parseRewrite();
}
self::boot();
}
/**
* 普通路由解析
*/
public static function parseByCommonRouter()
{
$router = isset($_GET['r']) ? explode(DIRECTORY_SEPARATOR, $_GET['r']) : ['index', 'index'];
self::$contrallerName = ucfirst(strtolower($router[0]));
self::$actionName = isset($router[1]) ? strtolower($router[1]) : Env::get('DEFAULT_ACTION');
}
/**
* URL重寫路由解析
*/
public static function parseRewrite()
{
if (strpos(self::$uri, "?")) {
$router = substr(self::$uri, 0, strpos(self::$uri, "?"));
} else {
$router = self::$uri;
}
if ($router == DIRECTORY_SEPARATOR) {
$router = ['index', 'index'];
}
is_string($router) && $routerUri = trim($router, DIRECTORY_SEPARATOR);
//自定義路徑
$routersArr = require CONF_PATH . 'routes.php';
if (!empty($routerUri) && !empty($routersArr['ROUTES'][$routerUri])) {
$routerUri = $routersArr['ROUTES'][$routerUri]['action'];
}
!is_array($router) && $router = explode(DIRECTORY_SEPARATOR, $routerUri);
self::$contrallerName = ucfirst(strtolower($router[0]));
self::$actionName = isset($router[1]) ? strtolower($router[1]) : Env::get('DEFAULT_ACTION');
}
/**
* 路由執行
*/
public static function boot()
{
define('CONTROLLER', self::$contrallerName);
define('ACTION', self::$contrallerName);
define('LOCAL_URL', createUrl(self::$contrallerName . DIRECTORY_SEPARATOR . self::$actionName));
$controllerName = 'controller\\' . self::$contrallerName;
if (!class_exists($controllerName)) {
echo self::$contrallerName . " does not defined";
exit();
}
$controller = new $controllerName();
if (!method_exists($controller, self::$actionName)) {
echo self::$actionName . " does not defined";
exit();
}
call_user_func([
$controller,
self::$actionName,
]);
}
private static function setDebug()
{
if (Env::get('DEBUG')) {
ini_set('display_errors', 1);
error_reporting(-1);
} else {
ini_set('display_errors', 0);
}
}
}
Controller基類
system/core/Controller.php
<?php
namespace core;
abstract class Controller
{
protected function render($viewFile, $data = null)
{
View::display($viewFile, $data);
}
public function assign($tplVar, $value = '')
{
View::assign($tplVar, $value);
}
}
Model基類
system/core/Model.php
<?php
namespace core;
abstract class Model
{
}
View基類
system/core/View.php
<?php
namespace core;
class View
{
private static $templateFile;
public static $_var = array();
public static $_foreachmark = '';
public static $_foreach = array();
public static $_temp_key = array(); // 臨時存放 foreach 里 key 的數組
public static $_temp_val = array(); // 臨時存放 foreach 里 item 的數組
public static $_patchstack = '';
public static $_nowtime = null;
function __construct()
{
self::$_nowtime = time();
header('Content-type: text/html; charset=utf-8');
}
/**
* 展示頁面
* @param $viewFile
* @param $data
*/
public static function display($viewFile, $data)
{
//賦值給變量self::$_var
if (is_array($data)) {
foreach ($data as $datakey => $dataValue) {
if ($dataValue != '') {
self::assign($datakey, $dataValue);
}
}
}
$content = self::fetch($viewFile);
echo $content;
}
private static function fetch($viewFile)
{
$filename = self::checkTemplate($viewFile);
$content = self::makeCompiled($filename);
return $content;
}
/**
* 編譯模板函數
* @access public
* @param string $filename
* @return sring 編譯后文件地址
*/
private static function makeCompiled($filename)
{
$source = '';
if (file_exists($filename)) {
$source = self::fetchStr(@file_get_contents($filename));
$source = self::_eval($source);
//$source = self::_require($source);
}
return $source;
}
private static function _eval($content)
{
ob_start();
eval('?' . '>' . trim($content));
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* 處理字符串函數
* @access public
* @param string $source
* @return sring
*/
private static function fetchStr($source)
{
//return preg_replace("/{([^\}\{\n]*)}/e", "\self::select('\\1');", $source);
return preg_replace_callback("/{([^\}\{\n]*)}/", function ($r) {
return self::select($r[1]);
}, $source);
}
/**
* 處理{}標簽
* @access public
* @param string $tag
* @return sring
*/
private static function select($tag)
{
$tag = stripslashes(trim($tag));
if (empty($tag)) {
return '{}';
} elseif ($tag{0} == '*' && substr($tag, -1) == '*') {
// 注釋部分
return '';
} elseif ($tag{0} == '$') {
// 變量
return '<?php echo ' . self::get_val(substr($tag, 1)) . '; ?>';
} elseif ($tag{0} == '/') {
// 結束 tag
switch (substr($tag, 1)) {
case 'if':
return '<?php endif; ?>';
break;
case 'foreach':
if (self::$_foreachmark == 'foreachelse') {
$output = '<?php endif; unset($_from); ?>';
} else {
array_pop(self::$_patchstack);
$output = '<?php endforeach; endif; unset($_from); ?>';
}
$output .= "<?php self::pop_vars(); ?>";
return $output;
break;
case 'literal':
return '';
break;
default:
return '{' . $tag . '}';
break;
}
} else {
$tag_array = explode(' ', $tag);
$tag_sel = array_shift($tag_array);
switch ($tag_sel) {
case 'if':
return self::_compileIfTag(substr($tag, 3));
break;
case 'else':
return '<?php else: ?>';
break;
case 'elseif':
return self::_compileIfTag(substr($tag, 7), true);
break;
case 'foreachelse':
self::$_foreachmark = 'foreachelse';
return '<?php endforeach; else: ?>';
break;
case 'foreach':
self::$_foreachmark = 'foreach';
if (!isset(self::$_patchstack)) {
self::$_patchstack = array();
}
return self::_compileForeachStart(substr($tag, 8));
break;
case 'assign':
$t = self::getPara(substr($tag, 7), 0);
if ($t['value']{0} == '$') {
/* 如果傳進來的值是變量,就不用用引號 */
$tmp = 'self::assign(\'' . $t['var'] . '\',' . $t['value'] . ');';
} else {
$tmp = 'self::assign(\'' . $t['var'] . '\',\'' . addcslashes($t['value'], "'") . '\');';
}
return '<?php ' . $tmp . ' ?>';
break;
case 'include':
$t = self::getPara(substr($tag, 8), 0);
if (substr($t[file], -4, 4) != 'html') {
$code = var_export(self::$_var[$t['inc_var']], 1);
if ($t['inc_var']) {
return '<?php self::assign(\'inc_var\',' . $code . ');echo self::fetch(' . "$t[file]" . '); ?>';
} else {
return '<?php echo self::fetch(' . "$t[file]" . '); ?>';
}
} else {
$code = var_export(self::$_var[$t['inc_var']], 1);
if ($t['inc_var'])
return '<?php self::assign(\'inc_var\',' . $code . ');echo self::fetch(' . "'$t[file]'" . '); ?>';
else
return '<?php echo self::fetch(' . "'$t[file]'" . '); ?>';
}
break;
case 'insert_scripts':
$t = self::getPara(substr($tag, 15), 0);
return '<?php echo self::smarty_insert_scripts(' . self::makeArray($t) . '); ?>';
break;
case 'create_pages':
$t = self::getPara(substr($tag, 13), 0);
return '<?php echo self::smarty_create_pages(' . self::makeArray($t) . '); ?>';
break;
case 'insert' :
$t = self::getPara(substr($tag, 7), false);
$out = "<?php \n" . '$k = ' . preg_replace("/(\'\\$[^,]+)/e", "stripslashes(trim('\\1','\''));", var_export($t, true)) . ";\n";
$out .= 'echo $k[\'name\'] . \'|\' . base64_encode(serialize($k));' . "\n?>";
return $out;
break;
case 'literal':
return '';
break;
case 'cycle' :
$t = self::getPara(substr($tag, 6), 0);
return '<?php echo self::cycle(' . self::makeArray($t) . '); ?>';
break;
case 'html_options':
$t = self::getPara(substr($tag, 13), 0);
return '<?php echo self::html_options(' . self::makeArray($t) . '); ?>';
break;
case 'html_select_date':
$t = self::getPara(substr($tag, 17), 0);
return '<?php echo self::html_select_date(' . self::makeArray($t) . '); ?>';
break;
case 'html_radios':
$t = self::getPara(substr($tag, 12), 0);
return '<?php echo self::html_radios(' . self::makeArray($t) . '); ?>';
break;
case 'html_select_time':
$t = self::getPara(substr($tag, 12), 0);
return '<?php echo self::html_select_time(' . self::makeArray($t) . '); ?>';
break;
case 'function' :
$t = self::getPara(substr($tag, 8), false);
$out = "<?php \n" . '$k = ' . preg_replace("/(\'\\$[^,]+)/e", "stripslashes(trim('\\1','\''));", var_export($t, true)) . ";\n";
$out .= 'echo $k[\'name\'](';
$first = true;
foreach ($t as $n => $v) {
if ($n != "name") {
if ($first) {
$out .= '$k[\'' . $n . '\']';
$first = false;
} else {
$out .= ',$k[\'' . $n . '\']';
}
}
}
$out .= ');' . "\n?>";
return $out;
break;
case 'url_wap' :
$reg_text = "/\"([^\"]+)\"/";
preg_match_all($reg_text, $tag, $matches);
if (count($matches[0]) > 0) {
//url格式正確
$param_str = "\"\"";
if (isset($matches[0][1]) && $matches[0][1] != '') {
//有額外傳參
preg_match_all("/[$]([^\"&]+)/", $matches[0][1], $param_matches);
$replacement = array();
$finder = array();
if (count($param_matches[0]) > 0) {
foreach ($param_matches[0] as $m_item) {
$finder[] = $m_item;
}
//有參數
foreach ($param_matches[1] as $p_item) {
$p_item_arr = explode(".", $p_item);
$var_str = '".self::$_var';
foreach ($p_item_arr as $var_item) {
$var_str = $var_str . "['" . $var_item . "']";
}
$var_str .= '."';
$replacement[] = $var_str;
}
}
$param_str = str_replace($finder, $replacement, $matches[0][1]);
}
//$app_index = $matches[1][0];
$route = $matches[1][0];
if (empty($route))
$route = "index";
$code = "<?php\r\n";
$code .= "echo parse_url_tag_wap(\"";
$code .= "u:";
$code .= $route . "|\".";
$code .= $param_str . ".";
$code .= "\"\"); \r\n";
$code .= "?>";
return $code;
} else {
return '{' . $tag . '}';
}
break;
case 'url' :
$reg_text = "/\"([^\"]+)\"/";
preg_match_all($reg_text, $tag, $matches);
if (count($matches[0]) > 0) {
//url格式正確
$param_str = "\"\"";
if (isset($matches[0][1]) && $matches[0][1] != '') {
//有額外傳參
//return print_r($matches[0][2],true);
preg_match_all("/[$]([^\"&]+)/", $matches[0][1], $param_matches);
$replacement = array();
$finder = array();
if (count($param_matches[0]) > 0) {
foreach ($param_matches[0] as $m_item) {
$finder[] = $m_item;
}
//有參數
foreach ($param_matches[1] as $p_item) {
$p_item_arr = explode(".", $p_item);
$var_str = '".self::$_var';
foreach ($p_item_arr as $var_item) {
$var_str = $var_str . "['" . $var_item . "']";
}
$var_str .= '."';
$replacement[] = $var_str;
}
}
$param_str = str_replace($finder, $replacement, $matches[0][1]);
}
//$app_index = $matches[1][0];
$route = $matches[1][0];
if (empty($route))
$route = "index";
$code = "<?php\r\n";
$code .= "echo parse_url_tag(\"";
$code .= "u:";
$code .= $route . "|\".";
$code .= $param_str . ".";
$code .= "\"\"); \r\n";
$code .= "?>";
return $code;
} else {
return '{' . $tag . '}';
}
break;
default:
return '{' . $tag . '}';
break;
}
}
}
/**
* 處理smarty標簽中的變量標簽
* @access public
* @param string $val
* @return bool
*/
private static function get_val($val)
{
if (strrpos($val, '[') !== false) {
$val = preg_replace("/\[([^\[\]]*)\]/eis", "'.'.str_replace('$','\$','\\1')", $val);
}
if (strrpos($val, '|') !== false) {
$moddb = explode('|', $val);
$val = array_shift($moddb);
}
if (empty($val)) {
return '';
}
if (strpos($val, '.$') !== false) {
$all = explode('.$', $val);
foreach ($all as $key => $val) {
$all[$key] = $key == 0 ? self::makeVar($val) : '[' . self::makeVar($val) . ']';
}
$p = implode('', $all);
} else {
$p = self::makeVar($val);
}
if (!empty($moddb)) {
foreach ($moddb as $key => $mod) {
$s = explode(':', $mod);
switch ($s[0]) {
case 'escape':
$s[1] = trim($s[1], '"');
if ($s[1] == 'html') {
$p = 'htmlspecialchars(' . $p . ')';
} elseif ($s[1] == 'url') {
$p = 'urlencode(' . $p . ')';
} elseif ($s[1] == 'decode_url') {
$p = 'urldecode(' . $p . ')';
} elseif ($s[1] == 'quotes') {
$p = 'addslashes(' . $p . ')';
} elseif ($s[1] == 'u8_url') {
if (EC_CHARSET != 'utf-8') {
$p = 'urlencode(ecs_iconv("' . EC_CHARSET . '", "utf-8",' . $p . '))';
} else {
$p = 'urlencode(' . $p . ')';
}
} else {
$p = 'htmlspecialchars(' . $p . ')';
}
break;
case 'nl2br':
$p = 'nl2br(' . $p . ')';
break;
case 'default':
$s[1] = $s[1]{0} == '$' ? self::get_val(substr($s[1], 1)) : "'$s[1]'";
$p = 'empty(' . $p . ') ? ' . $s[1] . ' : ' . $p;
break;
case 'truncate':
$p = 'sub_str(' . $p . ",$s[1])";
break;
case 'strip_tags':
$p = 'strip_tags(' . $p . ')';
break;
default:
# code...
break;
}
}
}
return $p;
}
/**
* 處理去掉$的字符串
* @access public
* @param string $val
* @return bool
*/
private static function makeVar($val)
{
if (strrpos($val, '.') === false) {
if (isset(self::$_var[$val]) && isset(self::$_patchstack[$val])) {
$val = self::$_patchstack[$val];
}
$p = 'self::$_var[\'' . $val . '\']';
} else {
$t = explode('.', $val);
$_var_name = array_shift($t);
if (isset(self::$_var[$_var_name]) && isset(self::$_patchstack[$_var_name])) {
$_var_name = self::$_patchstack[$_var_name];
}
if ($_var_name == 'smarty') {
$p = self::_compileSmartyRef($t);
} else {
$p = 'self::$_var[\'' . $_var_name . '\']';
}
foreach ($t as $val) {
$p .= '[\'' . $val . '\']';
}
}
return $p;
}
/**
* 處理insert外部函數/需要include運行的函數的調用數據
*
* @access public
* @param string $val
* @param int $type
*
* @return array
*/
private static function getPara($val, $type = 1) // 處理insert外部函數/需要include運行的函數的調用數據
{
$pa = self::strTrim($val);
foreach ($pa as $value) {
if (strrpos($value, '=')) {
list($a, $b) = explode('=', str_replace(array(' ', '"', "'", '"'), '', $value));
if ($b{0} == '$') {
if ($type) {
eval('$para[\'' . $a . '\']=' . self::get_val(substr($b, 1)) . ';');
} else {
$para[$a] = self::get_val(substr($b, 1));
}
} else {
$para[$a] = $b;
}
}
}
return $para;
}
/**
* 處理if標簽
*
* @access public
* @param string $tag_args
* @param bool $elseif
*
* @return string
*/
private static function _compileIfTag($tag_args, $elseif = false)
{
preg_match_all('/\-?\d+[\.\d]+|\'[^\'|\s]*\'|"[^"|\s]*"|[\$\w\.]+|!==|===|==|!=|<>|<<|>>|<=|>=|&&|\|\||\(|\)|,|\!|\^|=|&|<|>|~|\||\%|\+|\-|\/|\*|\@|\S/', $tag_args, $match);
$tokens = $match[0];
// make sure we have balanced parenthesis
$token_count = array_count_values($tokens);
if (!empty($token_count['(']) && $token_count['('] != $token_count[')']) {
// $this->_syntax_error('unbalanced parenthesis in if statement', E_USER_ERROR, __FILE__, __LINE__);
}
for ($i = 0, $count = count($tokens); $i < $count; $i++) {
$token = &$tokens[$i];
switch (strtolower($token)) {
case 'eq':
$token = '==';
break;
case 'ne':
case 'neq':
$token = '!=';
break;
case 'lt':
$token = '<';
break;
case 'le':
case 'lte':
$token = '<=';
break;
case 'gt':
$token = '>';
break;
case 'ge':
case 'gte':
$token = '>=';
break;
case 'and':
$token = '&&';
break;
case 'or':
$token = '||';
break;
case 'not':
$token = '!';
break;
case 'mod':
$token = '%';
break;
default:
if ($token[0] == '$') {
$token = self::get_val(substr($token, 1));
}
break;
}
}
if ($elseif) {
return '<?php elseif (' . implode(' ', $tokens) . '): ?>';
} else {
return '<?php if (' . implode(' ', $tokens) . '): ?>';
}
}
/**
* 處理foreach標簽
*
* @access public
* @param string $tag_args
*
* @return string
*/
private static function _compileForeachStart($tag_args)
{
$attrs = self::getPara($tag_args, 0);
$from = $attrs['from'];
if (isset(self::$_var[$attrs['item']]) && !isset(self::$_patchstack[$attrs['item']])) {
self::$_patchstack[$attrs['item']] = $attrs['item'] . '_' . str_replace(array(' ', '.'), '_', microtime());
$attrs['item'] = self::$_patchstack[$attrs['item']];
} else {
self::$_patchstack[$attrs['item']] = $attrs['item'];
}
$item = self::get_val($attrs['item']);
if (!empty($attrs['key'])) {
$key = $attrs['key'];
$key_part = self::get_val($key) . ' => ';
} else {
$key = null;
$key_part = '';
$attrs['key'] = '';
}
if (!empty($attrs['name'])) {
$name = $attrs['name'];
} else {
$name = null;
}
$output = '<?php ';
$output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }; ";
//$output .= "self::push_vars('".($attrs['key']?:'')."', '{$attrs['item']}');";
if (!empty($name)) {
$foreach_props = "self::\$_foreach['$name']";
$output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
$output .= "if ({$foreach_props}['total'] > 0):\n";
$output .= " foreach (\$_from as $key_part$item):\n";
$output .= " {$foreach_props}['iteration']++;\n";
} else {
$output .= "if (count(\$_from)):\n";
$output .= " foreach (\$_from as $key_part$item):\n";
}
return $output . '?>';
}
/**
* 彈出臨時數組的最后一個
*
* @return void
*/
private static function pop_vars()
{
$key = array_pop(self::$_temp_key);
$val = array_pop(self::$_temp_val);
if (!empty($key)) {
eval($key);
}
}
/**
* 將 foreach 的 key, item 放入臨時數組
* @param mixed $key
* @param mixed $val
* @return void
*/
/* private static function push_vars($key='', $val='')
{
if (!empty($key)) {
array_push(self::$_temp_key, "self::\$_var['$key']='" . self::$_var[$key] . "';");
}
if (!empty($val)) {
array_push(self::$_temp_val, "self::\$_var['$val']='" . self::$_var[$val] . "';");
}
}*/
private static function html_options($arr)
{
$selected = $arr['selected'];
if ($arr['options']) {
$options = (array)$arr['options'];
} elseif ($arr['output']) {
if ($arr['values']) {
foreach ($arr['output'] as $key => $val) {
$options["{$arr[values][$key]}"] = $val;
}
} else {
$options = array_values((array)$arr['output']);
}
}
$out = '';
if ($options) {
foreach ($options as $key => $val) {
$out .= $key == $selected ? "<option value=\"$key\" selected>$val</option>" : "<option value=\"$key\">$val</option>";
}
}
return $out;
}
private static function html_select_date($arr)
{
$pre = $arr['prefix'];
if (isset($arr['time'])) {
if (intval($arr['time']) > 10000) {
$arr['time'] = gmdate('Y-m-d', $arr['time'] + 8 * 3600);
}
$t = explode('-', $arr['time']);
$year = strval($t[0]);
$month = strval($t[1]);
$day = strval($t[2]);
}
$now = gmdate('Y', self::$_nowtime);
if (isset($arr['start_year'])) {
if (abs($arr['start_year']) == $arr['start_year']) {
$startyear = $arr['start_year'];
} else {
$startyear = $arr['start_year'] + $now;
}
} else {
$startyear = $now - 3;
}
if (isset($arr['end_year'])) {
if (strlen(abs($arr['end_year'])) == strlen($arr['end_year'])) {
$endyear = $arr['end_year'];
} else {
$endyear = $arr['end_year'] + $now;
}
} else {
$endyear = $now + 3;
}
$out = "<select name=\"{$pre}Year\">";
for ($i = $startyear; $i <= $endyear; $i++) {
$out .= $i == $year ? "<option value=\"$i\" selected>$i</option>" : "<option value=\"$i\">$i</option>";
}
if ($arr['display_months'] != 'false') {
$out .= "</select> <select name=\"{$pre}Month\">";
for ($i = 1; $i <= 12; $i++) {
$out .= $i == $month ? "<option value=\"$i\" selected>" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>" : "<option value=\"$i\">" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>";
}
}
if ($arr['display_days'] != 'false') {
$out .= "</select> <select name=\"{$pre}Day\">";
for ($i = 1; $i <= 31; $i++) {
$out .= $i == $day ? "<option value=\"$i\" selected>" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>" : "<option value=\"$i\">" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>";
}
}
return $out . '</select>';
}
private static function html_radios($arr)
{
$name = $arr['name'];
$checked = $arr['checked'];
$options = $arr['options'];
$out = '';
foreach ($options as $key => $val) {
$out .= $key == $checked ? "<input type=\"radio\" name=\"$name\" value=\"$key\" checked> {$val} "
: "<input type=\"radio\" name=\"$name\" value=\"$key\"> {$val} ";
}
return $out;
}
private static function html_select_time($arr)
{
$pre = $arr['prefix'];
if (isset($arr['time'])) {
$arr['time'] = gmdate('H-i-s', $arr['time'] + 8 * 3600);
$t = explode('-', $arr['time']);
$hour = strval($t[0]);
$minute = strval($t[1]);
$second = strval($t[2]);
}
$out = '';
if (!isset($arr['display_hours'])) {
$out .= "<select name=\"{$pre}Hour\">";
for ($i = 0; $i <= 23; $i++) {
$out .= $i == $hour ? "<option value=\"$i\" selected>" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>" : "<option value=\"$i\">" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>";
}
$out .= "</select> ";
}
if (!isset($arr['display_minutes'])) {
$out .= "<select name=\"{$pre}Minute\">";
for ($i = 0; $i <= 59; $i++) {
$out .= $i == $minute ? "<option value=\"$i\" selected>" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>" : "<option value=\"$i\">" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>";
}
$out .= "</select> ";
}
if (!isset($arr['display_seconds'])) {
$out .= "<select name=\"{$pre}Second\">";
for ($i = 0; $i <= 59; $i++) {
$out .= $i == $second ? "<option value=\"$i\" selected>" . str_pad($i, 2, '0', STR_PAD_LEFT) . "</option>" : "<option value=\"$i\">$i</option>";
}
$out .= "</select> ";
}
return $out;
}
private static function cycle($arr)
{
static $k, $old;
$value = explode(',', $arr['values']);
if ($old != $value) {
$old = $value;
$k = 0;
} else {
$k++;
if (!isset($old[$k])) {
$k = 0;
}
}
echo $old[$k];
}
private static function makeArray($arr)
{
$out = '';
foreach ($arr as $key => $val) {
if ($val{0} == '$') {
$out .= $out ? ",'$key'=>$val" : "array('$key'=>$val";
} else {
$out .= $out ? ",'$key'=>'$val'" : "array('$key'=>'$val'";
}
}
return $out . ')';
}
/**
* 處理smarty開頭的預定義變量
* @access public
* @param array $indexes
* @return string
*/
private static function _compileSmartyRef(&$indexes)
{
$_ref = $indexes[0];
switch ($_ref) {
case 'now':
$compiled_ref = 'time()';
break;
case 'foreach':
array_shift($indexes);
$_var = $indexes[0];
$_propname = $indexes[1];
switch ($_propname) {
case 'index':
array_shift($indexes);
$compiled_ref = "(self::\$_foreach['$_var']['iteration'] - 1)";
break;
case 'first':
array_shift($indexes);
$compiled_ref = "(self::\$_foreach['$_var']['iteration'] <= 1)";
break;
case 'last':
array_shift($indexes);
$compiled_ref = "(self::\$_foreach['$_var']['iteration'] == self::\$_foreach['$_var']['total'])";
break;
case 'show':
array_shift($indexes);
$compiled_ref = "(self::\$_foreach['$_var']['total'] > 0)";
break;
default:
$compiled_ref = "self::\$_foreach['$_var']";
break;
}
break;
case 'get':
$compiled_ref = '$_GET';
break;
case 'post':
$compiled_ref = '$_POST';
break;
case 'cookies':
$compiled_ref = '$_COOKIE';
break;
case 'env':
$compiled_ref = '$_ENV';
break;
case 'server':
$compiled_ref = '$_SERVER';
break;
case 'request':
$compiled_ref = '$_REQUEST';
break;
case 'session':
$compiled_ref = '$_SESSION';
break;
default:
break;
}
array_shift($indexes);
return $compiled_ref;
}
private static function smarty_insert_scripts($args)
{
static $scripts = array();
$arr = explode(',', str_replace(' ', '', $args['files']));
$str = '';
foreach ($arr as $val) {
if (in_array($val, $scripts) == false) {
$scripts[] = $val;
if ($val{0} == '.') {
$str .= '<script type="text/javascript" src="' . $val . '"></script>';
} else {
$str .= '<script type="text/javascript" src="js/' . $val . '"></script>';
}
}
}
return $str;
}
private static function smarty_create_pages($params)
{
extract($params);
if (empty($page)) {
$page = 1;
}
if (!empty($count)) {
$str = "<option value='1'>1</option>";
$min = min($count - 1, $page + 3);
for ($i = $page - 3; $i <= $min; $i++) {
if ($i < 2) {
continue;
}
$str .= "<option value='$i'";
$str .= $page == $i ? " selected='true'" : '';
$str .= ">$i</option>";
}
if ($count > 1) {
$str .= "<option value='$count'";
$str .= $page == $count ? " selected='true'" : '';
$str .= ">$count</option>";
}
} else {
$str = '';
}
return $str;
}
private static function strTrim($str)
{
/* 處理'a=b c=d k = f '類字符串,返回數組 */
while (strpos($str, '= ') != 0) {
$str = str_replace('= ', '=', $str);
}
while (strpos($str, ' =') != 0) {
$str = str_replace(' =', '=', $str);
}
return explode(' ', trim($str));
}
private static function _require($filename)
{
ob_start();
ob_implicit_flush(0);
include $filename;
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* 注冊變量
* @param $tplVar
* @param string $value
*/
public static function assign($tplVar, $value = '')
{
if (is_array($tplVar)) {
foreach ($tplVar as $key => $val) {
if ($key != '') {
self::$_var[$key] = $val;
}
}
} else {
if ($tplVar != '') {
self::$_var[$tplVar] = $value;
}
}
}
/**
* 驗證模板文件的存在
* @param $viewFile
* @return string
*/
public static function checkTemplate($viewFile)
{
$viewFolder = PUBLIC_PATH . 'themes' . DIRECTORY_SEPARATOR . 'default' . DIRECTORY_SEPARATOR;
if (empty($viewFile)) {
self::$templateFile = $viewFolder . CONTROLLER . DIRECTORY_SEPARATOR . ACTION . '.html';
} else {
$viewFileArr = explode(DIRECTORY_SEPARATOR, $viewFile);
self::$templateFile = $viewFolder . $viewFileArr[0] . DIRECTORY_SEPARATOR . $viewFileArr[1];
}
if (file_exists(self::$templateFile)) {
return self::$templateFile;
} else {
//拋出模板文件不存在異常
echo "template file does not exist";
exit();
}
}
}
msql類
system/database/DB.php
<?php
namespace database;
use core\Env;
class DB
{
public static $__pdo = null; // 默認PDO對象
public static $__is_mysql = null; // 默認是否mysql數據庫
public static $__dsn = "mysql:host=%s;port=%s;dbname=%s;charset=%s;"; // DSN
public static $__host = ""; // 默認主機
public static $__port = ""; // 端口
public static $__username = ""; // 默認賬戶
public static $__password = ""; // 默認密碼
public static $__dbname = ""; // 默認數據庫名稱
public static $__charset = ""; // 默認字符集
public static $__prefix = ""; // 默認表前綴
protected $_pdo = null; // PDO對象
protected $_is_mysql = null; // 默認是否mysql數據庫
protected static $_prefix = null; // 表前綴
protected static $_table = null; // 表名
protected static $_alias = null; // 表別名
protected static $_fulltable = null; // 表全名
protected static $_instance = false;
protected $_pk = null; // 主鍵
private $_keywords = array(); // keywords
private $_columns = array(); // columns
private $_joins = array(); // joins
private $_wheres = array(); // where
private $_wheres_params = array(); // where params
private $_groups = array(); // group
private $_havings = array(); // having
private $_havings_params = array(); // having params
private $_orders = array(); // order
private $_limit = null; // limit
private $_offset = null; // offset
private $_for_update = ""; // read lock
private $_lock_in_share_mode = ""; // write lock
private $_count_wheres = array(); // count where
private $_count_wheres_params = array(); // count where params
private $_exp = array('eq' => '=', 'ne' => '<>', 'gt' => '>', 'ge' => '>=', 'lt' => '<', 'le' => '<=',
'not like' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN',
'not between' => 'NOT BETWEEN',);
private $_incDbLinkNums = 0;
public $_sql = ""; // sql
public $_params = array(); // params
public static function getInstance()
{
if (self::$_instance == false) {
self::$_instance = new self();
}
return self::$_instance;
}
// 獲取參數類型
private static function type($param)
{
static $types = array(
"boolean" => \PDO::PARAM_BOOL,
"NULL" => \PDO::PARAM_NULL,
"double" => \PDO::PARAM_INT,
"integer" => \PDO::PARAM_INT,
"string" => \PDO::PARAM_STR,
);
$type = gettype($param);
return array_key_exists($type, $types) ? $types[$type] : \PDO::PARAM_STR;
}
public function __construct()
{
self::$__host = Env::get('DB_HOST') ? Env::get('DB_HOST') : '127.0.0.1';
self::$__port = Env::get('DB_PORT') ? Env::get('DB_PORT') : '3306';
self::$__username = Env::get('DB_USER') ? Env::get('DB_USER') : 'root';
self::$__password = Env::get('DB_PWD') ? Env::get('DB_PWD') : 'root';
self::$__dbname = Env::get('DB_NAME') ? Env::get('DB_NAME') : 'test';
self::$__charset = Env::get('DB_CHATSET') ? Env::get('DB_CHATSET') : 'utf8';
}
// 設置表前綴
public function prefix($prefix = "")
{
self::$_prefix = $prefix;
self::$_fulltable = self::$_prefix . self::$_table;
return $this;
}
// 設置表名
public static function table($table = "")
{
if (strpos($table, " as ")) {
list($table, $alias) = explode(" as ", $table);
self::$_alias = $alias;
}
self::$_table = $table;
self::$_fulltable = self::$_prefix . self::$_table;
return self::getInstance();
}
// 設置表別名
public function alias($alias = "")
{
self::$_alias = $alias;
return $this;
}
// 設置主鍵名稱
public function pk($pk = "id")
{
$this->_pk = $pk;
return $this;
}
// 設置MySQL關鍵字
public function keyword($keyword)
{
if ($this->is_mysql()) {
$this->_keywords[] = $keyword;
}
return $this;
}
// 設置SQL_CALC_FOUND_ROWS關鍵字
public function calcFoundRows()
{
return $this->keyword("SQL_CALC_FOUND_ROWS");
}
// column返回的列
public function select($column)
{
$this->_columns[] = $column;
return $this;
}
// leftjoin連表查詢
public function leftjoin($join, $cond)
{
list($table, $alias) = explode(" as ", $join);
$prefix = strpos($table, "`") === 0 ? "" : self::$__prefix;
if (empty($alias)) {
$this->_joins[] = sprintf("`%s%s` ON `%s`", $prefix, $table, $cond);
} else {
$this->_joins[] = sprintf("`%s%s` AS `%s` ON %s", $prefix, $table, $alias, $cond);
}
return $this;
}
// where查詢條件
public function where($where)
{
if (is_array($where)) {
$this->arrayWhere($where);
} else {
$args = array_slice(func_get_args(), 1);
$this->stringWhere($where, $args);
}
return $this;
}
private function stringWhere($where, $args)
{
$ws = explode("?", $where);
$where = array_shift($ws);
$params = array();
foreach ($ws as $i => $w) {
if (!empty($args) && is_array($args[$i])) {
$where .= "?" . str_repeat(",?", count($args[$i]) - 1) . $w;
$params = array_merge($params, $args[$i]);
} else {
$where .= "?" . $w;
!empty($args) && $params[] = $args[$i];
}
}
$this->_wheres[] = $where;
$this->_wheres_params = array_merge($this->_wheres_params, $params);
}
/**
* where數組分析
* @param $where
*/
private function arrayWhere($where)
{
$whereStr = '';
$operate = ' and ';
foreach ($where as $key => $val) {
$whereStr .= $this->parseWhereItem($key, $val);
$whereStr .= $operate;
}
$whereStr = substr($whereStr, 0, -strlen($operate));
$this->stringWhere($whereStr, '');
}
// where子單元分析
private function parseWhereItem($key, $val)
{
$whereStr = '';
if (is_array($val)) {
if (is_string($val[0])) {
$exp = strtolower($val[0]);
if (preg_match('/^(eq|ne|gt|ge|lt|le)$/', $exp)) { // 比較運算
$whereStr .= $key . ' ' . $this->_exp[$exp] . ' ?';
$this->_wheres_params[] = $val[1];
} elseif (preg_match('/^(not like|like)$/', $exp)) { // 模糊查找
if (is_array($val[1])) {
$likeLogic = isset($val[2]) ? strtolower($val[2]) : 'OR';
if (in_array($likeLogic, array('AND', 'OR', 'XOR'))) {
$like = array();
foreach ($val[1] as $item) {
$like[] = $key . ' ' . $this->_exp[$exp] . ' ?';
$this->_wheres_params[] = $item;
}
$whereStr .= '(' . implode(' ' . $likeLogic . ' ', $like) . ')';
}
} else {
$whereStr .= $key . ' ' . $this->_exp[$exp] . ' ?';
$this->_wheres_params[] = $val[1];
}
} elseif (preg_match('/^(not in|in)$/', $exp)) { // IN 運算
if (is_string($val[1])) {
$val[1] = explode(',', $val[1]);
}
$zone = '';
foreach ($val[1] as $valInItem) {
$zone .= "?,";
$this->_wheres_params[] = $valInItem;
}
$zone = rtrim($zone, ",");
$whereStr .= $key . ' ' . $this->_exp[$exp] . " ({$zone})";
} elseif (preg_match('/^(not between|between)$/', $exp)) { // BETWEEN運算
$data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
$whereStr .= $key . ' ' . $this->_exp[$exp] . ' ? AND ?';
$this->_wheres_params[] = $data[0];
$this->_wheres_params[] = $data[1];
} else {
throw new Exception('not_support_expressions_' . $val[0] . '=>' . $val[1]);
}
} else {
$count = count($val);
$rule = isset($val[$count - 1]) ? (is_array($val[$count - 1]) ? strtolower($val[$count - 1][0]) : strtolower($val[$count - 1])) : '';
if (in_array($rule, array('AND', 'OR', 'XOR'))) {
$count = $count - 1;
} else {
$rule = 'AND';
}
for ($i = 0; $i < $count; $i++) {
$whereStr .= $this->parseWhereItem($key, $val[$i]) . ' ' . $rule . ' ';
}
$whereStr = '( ' . substr($whereStr, 0, -4) . ' )';
}
} else {
$whereStr .= $key . ' = ?';
$this->_wheres_params[] = $val;
}
return $whereStr;
}
// group分組
public function group($group)
{
$this->_groups[] = $group;
return $this;
}
// having過濾條件
public function having($having)
{
$args = array_slice(func_get_args(), 1);
$ws = explode("?", $having);
$having = array_shift($ws);
$params = array();
foreach ($ws as $i => $w) {
if (is_array($args[$i])) {
$having .= "?" . str_repeat(",?", count($args[$i]) - 1) . $w;
$params = array_merge($params, $args[$i]);
} else {
$having .= "?" . $w;
$params[] = $args[$i];
}
}
$this->_havings[] = $having;
$this->_havings_params = array_merge($this->_havings_params, $params);
return $this;
}
// order排序
public function order($order)
{
$this->_orders[] = $order;
return $this;
}
// limit數據
public function limit($limit)
{
$this->_limit = intval($limit);
return $this;
}
// offset偏移
public function offset($offset)
{
$this->_offset = intval($offset);
return $this;
}
// 獨占鎖,不可讀不可寫
public function forUpdate()
{
$this->_for_update = " FOR UPDATE";
return $this;
}
// 共享鎖,可讀不可寫
public function lockInShareMode()
{
$this->_lock_in_share_mode = " LOCK IN SHARE MODE";
return $this;
}
// 設置和獲取PDO對象
public function pdo($pdo = null)
{
if ($pdo !== null && is_a($pdo, "\\PDO")) {
$this->_pdo = $pdo;
$this->_is_mysql = $this->_pdo->getAttribute(\PDO::ATTR_DRIVER_NAME) === "mysql";
return $this;
}
if (isset($this->_pdo)) {
return $this->_pdo;
}
if (isset(self::$__pdo)) {
return self::$__pdo;
}
$dsn = sprintf(self::$__dsn, self::$__host, self::$__port, self::$__dbname, self::$__charset);
$options = array(
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_STRINGIFY_FETCHES => false,
\PDO::ATTR_EMULATE_PREPARES => false,
);
self::$__pdo = new \PDO($dsn, self::$__username, self::$__password, $options);
if (empty(self::$__pdo) && $this->_incDbLinkNums <= 2) {
$this->_incDbLinkNums++;
$this->pdo();
}
self::$__is_mysql = self::$__pdo->getAttribute(\PDO::ATTR_DRIVER_NAME) === "mysql";
return self::$__pdo;
}
// 獲取當前PDO是否是mysql數據庫
public function is_mysql($is_mysql = null)
{
if ($is_mysql === null) {
return $this->_is_mysql !== null ? $this->_is_mysql : (self::$__is_mysql !== null ? self::$__is_mysql : false);
}
$this->_is_mysql = $is_mysql;
return $this;
}
// 事務開始
public function begin()
{
return $this->pdo()->beginTransaction();
}
// 事務提交
public function commit()
{
return $this->pdo()->commit();
}
// 事務回滾
public function rollBack()
{
return $this->pdo()->rollBack();
}
// sql查詢
public static function query($sql)
{
$params = array_slice(func_get_args(), 1);
return self::getInstance()->vquery($sql, $params);
}
// sql查詢
public function vquery($sql, $params = array())
{
/*if (strpos($sql, "'") !== false || strpos($sql, '"') !== false) {
throw new \LogicException("query is not right");
}*/
$this->_sql = $this->doTheSql($params, $sql);
$this->_params = $params;
$stmt = $this->pdo()->prepare($sql);
foreach ($params as $i => $param) {
$stmt->bindValue($i + 1, $param, self::type($param));
}
$stmt->executeResult = $stmt->execute();
$this->reset();
return $stmt;
}
// 組裝查詢數據
private function assembleData($columns = null, $isGetSql = false)
{
if (!empty($columns)) {
$this->_columns[] = $columns;
}
$keywords = empty($this->_keywords) ? "" : " " . implode(" ", $this->_keywords);
$columns = empty($this->_columns) ? "*" : implode(", ", $this->_columns);
$table = self::$_fulltable . (!empty(self::$_alias) && !empty($this->_joins) ? "` AS `" . self::$_alias : "");
$joins = empty($this->_joins) ? "" : " LEFT JOIN " . implode(" LEFT JOIN ", $this->_joins);
$wheres = empty($this->_wheres) ? "" : " WHERE " . implode(" AND ", $this->_wheres);
$groups = empty($this->_groups) ? "" : " GROUP BY " . implode(", ", $this->_groups);
$havings = empty($this->_havings) ? "" : " HAVING " . implode(" AND ", $this->_havings);
$orders = empty($this->_orders) ? "" : " ORDER BY " . implode(", ", $this->_orders);
$limit = !isset($this->_limit) ? "" : " LIMIT ?";
$offset = !isset($this->_offset) ? "" : " OFFSET ?";
$forUpdate = $this->_for_update;
$lockInShareMode = $this->_lock_in_share_mode;
$sql = sprintf("SELECT%s %s FROM `%s`%s%s%s%s%s%s%s%s%s", $keywords, $columns, $table, $joins, $wheres, $groups, $havings, $orders, $limit, $offset, $forUpdate, $lockInShareMode);
$params = array_merge($this->_wheres_params, $this->_havings_params);
if (isset($this->_limit)) {
$params[] = $this->_limit;
}
if (isset($this->_offset)) {
$params[] = $this->_offset;
}
$this->_count_wheres = $this->_wheres;
$this->_count_wheres_params = $this->_wheres_params;
if ($isGetSql) {
$this->_sql = $this->doTheSql($params, $sql);
return $this->_sql;
}
return $this->vquery($sql, $params);
}
/**
* 拼接sql
* @param $params
* @param $sql
* @return mixed
*/
private function doTheSql($params, $sql)
{
foreach ($params as $paramsItem) {
is_string($paramsItem) && $paramsItem = '"' . $paramsItem . '"';
$sql = substr_replace($sql, $paramsItem, strpos($sql, "?"), strlen("?"));
}
return $sql;
}
public function fetchAll()
{
return $this->assembleData()->fetchAll();
}
public function fetch()
{
return $this->assembleData()->fetch();
}
// 添加數據
public function insert(array $data)
{
$cols = array();
$sets = array();
$params = array();
foreach ($data as $col => $val) {
$cols[] = sprintf("`%s`", $col);
$sets[] = sprintf("`%s` = ?", $col);
$params[] = $val;
}
if ($this->is_mysql()) {
$sql = sprintf("INSERT INTO `%s` SET %s", self::$_fulltable, implode(", ", $sets));
} else {
$sql = sprintf("INSERT INTO `%s` (%s) VALUES (?%s)", self::$_fulltable, implode(", ", $cols), str_repeat(", ?", count($cols) - 1));
}
$affectRow = $this->vquery($sql, $params)->rowCount();
if ($affectRow) {
return $this->lastInsertId();
}
return false;
}
// 獲取自增ID
public function lastInsertId()
{
return $this->pdo()->lastInsertId();
}
// 獲取符合條件的行數
public function count()
{
if ($this->is_mysql()) {
return $this->vquery("SELECT FOUND_ROWS()")->fetchColumn();
} else {
$wheres = empty($this->_count_wheres) ? "" : " WHERE " . implode(" AND ", $this->_count_wheres);
$sql = sprintf("SELECT count(*) FROM `%s`%s", self::$_fulltable, $wheres);
return $this->vquery($sql, $this->_count_wheres_params)->fetchColumn();
}
}
// 批量插入數據
public function batchInsert(array $columns, array &$rows, $batch = 100)
{
$column = implode("`,`", $columns);
$value = ",(?" . str_repeat(",?", count($columns) - 1) . ")";
$params = array();
$len = count($rows);
for ($i = 0; $i < $len; $i++) {
$params = array_merge($params, $rows[$i]);
if (($i + 1) % $batch == 0) {
$sql = sprintf("INSERT INTO `%s` (`%s`) VALUES %s%s", self::$_fulltable, $column, substr($value, 1), str_repeat($value, $batch - 1));
$this->vquery($sql, $params);
$params = array();
}
}
if ($len % $batch > 0) {
$sql = sprintf("INSERT INTO `%s` (`%s`) VALUES %s%s", self::$_fulltable, $column, substr($value, 1), str_repeat($value, $len % $batch - 1));
$this->vquery($sql, $params);
}
return $this;
}
// 更新數據
public function update(array $data)
{
if (empty($this->_wheres)) {
throw new \LogicException("where is empty!");
}
$sets = array();
$params = array();
foreach ($data as $col => $val) {
$sets[] = sprintf("`%s` = ?", $col);
$params[] = $val;
}
$wheres = " WHERE " . implode(" AND ", $this->_wheres);
$orders = empty($this->_orders) ? "" : " ORDER BY " . implode(", ", $this->_orders);
$limit = !isset($this->_limit) ? "" : " LIMIT ?";
$sql = sprintf("UPDATE `%s` SET %s%s%s%s", self::$_fulltable, implode(", ", $sets), $wheres, $orders, $limit);
$params = array_merge($params, $this->_wheres_params);
if (isset($this->_limit)) {
$params[] = $this->_limit;
}
return $this->vquery($sql, $params)->rowCount();
}
// 替換數據
public function replace(array $data)
{
$sets = array();
$params = array();
foreach ($data as $col => $val) {
$sets[] = sprintf("`%s` = ?", $col);
$params[] = $val;
}
$sql = sprintf("REPLACE INTO `%s` SET %s", self::$_fulltable, implode(", ", $sets));
return $this->vquery($sql, $params);
}
// 刪除數據
public function delete()
{
if (empty($this->_wheres)) {
throw new \LogicException("WHERE is empty!");
}
$wheres = " WHERE " . implode(" AND ", $this->_wheres);
$orders = empty($this->_orders) ? "" : " ORDER BY " . implode(", ", $this->_orders);
$limit = !isset($this->_limit) ? "" : " LIMIT ?";
$sql = sprintf("DELETE FROM `%s`%s%s%s", self::$_fulltable, $wheres, $orders, $limit);
$params = $this->_wheres_params;
if (isset($this->_limit)) {
$params[] = $this->_limit;
}
return $this->vquery($sql, $params)->rowCount();
}
// 重置所有
public function reset()
{
$this->_debug = false;
$this->_keywords = array();
$this->_columns = array();
$this->_joins = array();
$this->_wheres = array();
$this->_wheres_params = array();
$this->_groups = array();
$this->_havings = array();
$this->_havings_params = array();
$this->_orders = array();
$this->_limit = null;
$this->_offset = null;
$this->_for_update = "";
$this->_lock_in_share_mode = "";
return $this;
}
// page分頁
public function page($page = null, $pagesize = 15)
{
$page = intval(isset($page) ? $page : (isset($_GET["p"]) ? $_GET["p"] : 1));
$pagesize = intval($pagesize);
$this->_limit = $pagesize;
$this->_offset = ($page - 1) * $pagesize;
return $this;
}
// pagination分頁
public function pagination($pagesize = 15)
{
$args = array_slice(func_get_args(), 1);
$pagination = new Pagination($this->count(), null, $pagesize);
if (!empty($format)) {
call_user_func_array(array($pagination, "setStatic"), $args);
}
return $pagination->show();
}
// 將選中行的指定字段加一
public function plus($col, $val = 1)
{
$args = array_slice(func_get_args(), 2);
$sets = array(sprintf("`%s` = `%s` + ?", $col, $col));
$vals = array($val);
while (count($args) > 1) {
$col = array_shift($args);
$val = array_shift($args);
$sets[] = sprintf("`%s` = `%s` + ?", $col, $col);
$vals[] = $val;
}
if (empty($this->_wheres)) {
throw new \LogicException("WHERE is empty!");
}
$wheres = " WHERE " . implode(" AND ", $this->_wheres);
$sql = sprintf("UPDATE `%s` SET %s%s", self::$_fulltable, implode(", ", $sets), $wheres);
$params = array_merge($vals, $this->_wheres_params);
$this->vquery($sql, $params);
return $this;
}
// 將選中行的指定字段加一
public function incr($col, $val = 1)
{
if (empty($this->_wheres)) {
throw new \LogicException("WHERE is empty!");
}
$wheres = " WHERE " . implode(" AND ", $this->_wheres);
$sql = sprintf("UPDATE `%s` SET `%s` = last_insert_id(`%s` + ?)%s", self::$_fulltable, $col, $col, $wheres);
$params = array_merge(array($val), $this->_wheres_params);
$this->vquery($sql, $params);
return $this->pdo()->lastInsertId();
}
// 根據主鍵查找行
public function find($id)
{
return $this->where(sprintf("`%s` = ?", $this->_pk), $id)->assembleData()->fetch();
}
// 添加數據
public function add(array $data)
{
return $this->insert($data);
}
// 編輯數據
public function edit(array $data)
{
if (!array_key_exists($this->_pk, $data)) {
throw new \LogicException("\$data must contains column {$this->_pk}!");
}
$pk_val = $data[$this->_pk];
unset($data[$this->_pk]);
return $this->where(sprintf("`%s` = ?", $this->_pk), $pk_val)->update($data);
}
// 添加數據
public function del($id)
{
return $this->where(sprintf("`%s` = ?", $this->_pk), $id)->delete();
}
// 保存數據,自動判斷是新增還是更新
public function save(array $data)
{
if (array_key_exists($this->_pk, $data)) {
return $this->edit($data);
} else {
return $this->add($data);
}
}
// 獲取外鍵數據
public function foreignKey(array $rows, $foreign_key, $columns = "*")
{
$ids = array_column($rows, $foreign_key);
if (empty($ids)) {
return new \PDOStatement();
}
$ids = array_unique($ids);
return $this->where(sprintf("`%s` IN (?)", $this->_pk), $ids)->assembleData($columns);
}
//獲取sql語句
public function getSql()
{
return $this->assembleData('', true);
}
}
應用
數據庫部署
在 SQL 中新建一個test 數據庫,增加一個users 表
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`user_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用戶id',
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '名稱',
PRIMARY KEY (`user_id`) USING BTREE,
UNIQUE INDEX `name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用戶表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, 'gsj1');
INSERT INTO `users` VALUES (2, 'gsj2');
INSERT INTO `users` VALUES (3, 'gsj3');
模型部署
app/model/IndexModel.php
<?php
namespace model;
use core\Model;
use database\DB;
class IndexModel extends Model
{
public function doSomething()
{
$sq = "Welcome to doopsPHP!";
return $sq;
}
public function getUsersList()
{
//sql查詢
/*$sql = "select user_id,name from users where user_id=1";
$res = DB::query($sql)->fetch(); //單條fetch(),多條fetchAll()*/
//插入數據
/*$data=['name'=>'gsj2019'];
DB::table('users')->insert($data); //返回主鍵id*/
//批量插入
/*$fields = ['name'];
for ($i=1; $i<=10; $i++) {
$rowsArr[] = array("gsj_".mt_rand(100, 500));
}
DB::table('users')->batchInsert($fields, $rowsArr);*/
// 刪除數據
//$res=DB::table('users')->where(['user_id' => 4])->delete();//返回影響條數
//更新數據
/*$data=['name'=>'gsj2020'];
$res=DB::table('users')->where(['user_id'=>4])->update($data); //返回影響條數*/
//獲取sql語句 getSql()
//$res=DB::table('users')->select("user_id,name")->getSql();
//全部查詢
//DB::table('users')->select("user_id,name")->fetchAll();
//查詢單行
//DB::table('users')->select("user_id,name")->where('user_id = ?', 1)->fetch();
//where條件查詢
$where = [
//'name'=>'gsj',
//'user_id'=>array('le', 3),
'user_id' => array('in', array(1, 2, 3)),
//'name'=>array('like', '%gsj%'),
//'user_id'=>array( 'between', "1,3" ),
];
$res=DB::table('users')->where($where)->fetchAll();
//注:ne不等于、gt大于、ge大于等于、lt小于、le小于等于、like像、not like不像
//in在范圍、not in不在范圍、between在…中間、not between不在…中間
//DB::table('users')->where('user_id = ? and name=?', 1,"gsj")->fetch();
//左連接
/*$res=DB::table('users as u')->select("u.user_id,u.name,ui.job")->where(['u.user_id'=>1])
->leftjoin('users_info as ui','u.user_id=ui.user_id')->fetch();*/
return $res;
}
}
控制器部署
app/controller/Index.php
<?php
namespace Controller;
use core\Controller;
use model\IndexModel;
class Index extends Controller
{
private $indexModel;
public function __construct()
{
$this->indexModel = new IndexModel();
}
/**
*
*/
public function index()
{
$result = $this->indexModel->doSomething();
$useArr = $this->indexModel->getUsersList();
$data = [
'sq' => $result,
'users' => $useArr,
];
$this->render('index/index.html', $data);
}
public function test()
{
$res = $this->indexModel->getUsersList();
echo "<pre>";
print_r($res);
die();
}
public function shop()
{
$arr = $_GET;
echo "<pre>";
print_r($arr);
die();
}
}
視圖部署
public/themes/default/index/index.html
<!DOCTYPE HTML>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<title>{$sq}</title>
<style type="text/css">
*{margin:0;padding:0}
body{background:#f5f6f7}
#myborder{background:#fff;width:600px;height:320px;position:fixed;left:50%;top:50%;z-index:11;margin:-200px 0 0 -350px;border-radius:5px}
#myTitle{height:50px;text-align:center;padding:30px;font-size:40px}
#myContent{height:50px;text-align:center;padding:30px;font-size:28px;color:#fff;background:#b9b9b9}
#myFoot{height:50px;text-align:center;padding:30px;font-size:22px}
</style>
</head>
<body>
<div id="myborder">
<div id="myTitle">
Congratulation
</div>
<div id="myContent">
{$sq}
<div>
{if $users}
{foreach from=$users key=users_key item=users_item}
{$users_key} => {$users_item.name}
{/foreach}
{/if}
</div>
</div>
<div id="myFoot">
精彩從現在開始
</div>
</div>
</body>
</html>
應用測試
訪問rul
顯示
智能推薦
ionic框架入門
1.Chocolatey Chocolatey是一個Windows上的包管理器,類似于linux上的yum和apt-get。 你可以在其官方網站上查看具體的使用說明。一般的安裝步驟應該是下面這樣: 一般來說,使用Chocolatey來安裝軟件的時候,需要以管理員的身份來運行命令提示符窗口。譯注:chocolatey的網站可能在國內訪問困難,導致上述安裝命令無法正常完成。請使用穩定的翻...
Mybatis框架入門
Mybatis官網:http://www.mybatis.org/mybatis-3/ Mybatis的介紹 Mybatis是一個操作數據庫的框架。最開始叫做ibatis,從apache基金會脫離,加入googleCode正式更名為MyBatis。最終現在mybatis的代碼托管在github mybatis架構介紹 1、 mybatis配置SqlMapConfig.xml,此文件作為mybati...
Spring框架入門
文章目錄 Java Spring框架是什么?它有哪些好處? Spring體系結構詳解 Spring目錄結構和基礎JAR包介紹 Spring IoC容器:BeanFactory和ApplicationContext 第一個Spring程序 Spring DI(依賴注入)的實現方式:屬性注入和構造注入 Spring Bean的配置及常用屬性 Spring實例化Bean的三種方法 Spring中Bean...
scrapy框架入門
scrapy框架入門 一、Scrapy框架介紹 1.框架簡介 Scrapy是純Python開發的一個高效,結構化的網頁抓取框架 Scrapy使用了Twisted 異步網絡庫來處理網絡通訊 Scrapy是為了爬取網站數據,提取結構性數據而編寫的應用框架 Scrapy用途廣泛,可以用于數據挖掘、監測和自動化測試 2.模塊安裝 scrapy支持Python2.7和python3.4以上版本 python...
Spring框架入門
Spring 框架概述 1.1. 什么是Spring Spring是分層的JavaSE/EE full-stack(一站式) 輕量級開源框架 分層: 來自JavaEE體系結構 (客戶端層、 web層、業務層、持久層 ) 服務器端三層結構 (web層、業務層、持久層) Servlet + JSP —- web層技術 &mdash...
猜你喜歡
Spring《框架入門》
Spring用的jar包之一部分 配置簡單的日志文件需要的jar包 Spring基本的xml配置文件 現在開始建java項目 新建Dao類,User類方便測試 測試類 其中ClassPathXmlApplicationContext通過將Spring的xml配置文件全名傳入構造方法中,返回一個實現ApplicationContext接口的對象,這時候配置文件中的信息已經全部掃描進去,生成的對象方法...
scrapy框架入門
scrapy框架 Scrapy是用純Python實現一個為了爬取網站數據、提取結構性數據而編寫的應用框架,用途非常廣泛。 框架的力量,用戶只需要定制開發幾個模塊就可以輕松的實現一個爬蟲,用來抓取網頁內容以及各種圖片,非常之方便。 Scrapy 使用了 Twisted’tw?st?d異步網絡框架來處理網絡通訊,可以加快我們的下載速度,不用自己去實現異步框架,并且包含了各種中間件接口,可以...
express框架入門
本篇講述express框架入門 安裝express-generator(可以快速創建一個應用框架):npm install express-generator -g 創建一個express項目:在命令行輸入express --view=(模板名稱) 項目名稱 我這里使用的是ejs模板,port是我的項目名稱,其支持的模板有:ejs|hbs|hjs|jade|pug|twig|vash,根據自己的需...
Hibernate框架入門
導讀 本文主要介紹hibernate的入門,主要包括以下內容:hibernate介紹、hibernate環境搭建、hibernate簡單測試、測試涉及的api詳解。 一、hibernate介紹 JDBC是Java操作數據庫的工具,我們可以使用jdbc來書寫并執行sql語句來操作數據庫,對于普通的業務,jdbc工具是完全可以勝任的,但但當任務復雜,特別是數據庫中表格很多的時候,jdbc就會顯得力不從...