263 lines
8.7 KiB
PHP
Raw Permalink Normal View History

2024-08-31 01:03:37 +08:00
<?php
/**
* model函数用于实例化一个模型文件的Model [不存在的模型 or 存在的模型]
* @param string $name Model名称;支持为空;支持表名(驼峰结构);支持模型名
* @param string $tablePrefix 表前缀
* @param mixed $connection 数据库连接信息
* @return Model
*
* eg:
* Model("User")->getInfo(1); //实例化model中的model实现
* Model("share_to")->find(1); //实例化库ModelBase-Model基类直接调用库
*/
function Model($name = '', $tablePrefix = '', $connection = '') {
static $cache = array();
if($name === '_destroy_'){$cache = array();return;} // 清除缓存;
$guid = strtolower($tablePrefix . '_' . $name);
if(is_string($connection)){
$guid .= '_'.$connection;
}else if($connection && is_array($connection)){
return new ModelBase($name, $tablePrefix, $connection);
}
// 没有该类则为表名或空model
if(!$connection){$connection = $GLOBALS['config']['database'];}
if(isset($cache[$guid])) return $cache[$guid];
if($name){//有该类的情况(已经引入了类)
$name = strtoupper($name[0]).substr($name,1);
$modelName = $name.'Model';
if( class_exists($modelName) ){
$cache[$guid] = new $modelName('',$tablePrefix, $connection);
return $cache[$guid];
}
}
$cache[$guid] = new ModelBase($name, $tablePrefix, $connection);
return $cache[$guid];
}
/**
* action函数用于实例化一个控制器文件的Action
* @param string $name 控制器名称
* @return Object
*
* eg: 控制器/model/ 插件方法/插件模块方法;
* Action('user.index')->appConfig();
* Action('UserModel')->count();
*
* Action('chartPlugin')->view(); //chartPlugin; plugin/chart/app.php;
* Action('chartPlugin.user.view')->listData(); // chartUserView;plugin/chart/controller/user/view.chass.php;
* Action('chartPlugin.userModel')->listData(); // chartUserModel;
*/
function Action($name = '') {
static $_cache = array();
$nameBefore = $name;
if(isset($_cache[$nameBefore])) return $_cache[$nameBefore];
$name = trim(str_replace('/','.',$name),'/');
$arr = explode('.',$name);
$mod = strtolower($arr[0]);
if( substr($mod,-6) == 'plugin'){
$name = substr($arr[0],0,-6);
$className = $name.'Plugin';
$file = 'app.php';
if(isset($arr[1]) && substr(strtolower($arr[1]),-5) == 'model'){
$className = $name.$arr[1];// chartUserModel
$file = "model/".$arr[1].".class.php";
}else if(count($arr) == 3){
$className = $name.$arr[1].$arr[2];//chartUserView
$file = "controller/".$arr[1]."/".$arr[2].".class.php";
}
$file = PLUGIN_DIR.$name.'/'.$file;
}else if( substr($mod,-5) == 'model'){
$name = substr($arr[0],0,-5);
return Model($name);
}else{
$className = $arr[0].$arr[1];
$file = CONTROLLER_DIR.$arr[0].'/'.$arr[1].'.class.php';
}
$guid = strtolower($className);
if (isset($_cache[$guid])) return $_cache[$guid];
if (is_file($file)){
include_once($file);
}
if (!class_exists($className)) {
return actionCallError("[$name => $className] class not exists!");
}
$_cache[$guid] = new $className();
$_cache[$nameBefore] = $_cache[$guid];
return $_cache[$guid];
}
/**
* 调用控制器,插件方法,或直接调用函数;
*
* 参数合并为数组; 类似于js的 apply($object,$args);
* ActionApply('user.index.appConfig',array("add",'123'));
*
* 支持:
* 1. 直接调用:函数,类方法,静态类方法;eg: 'clear_html', array($this,'pathInfo'), array('IO','exist');
* 2. 控制器方法; eg: 'user.index.appConfig';
* 3. 模型方法; eg: 'sourceModel.targetSpaceUpdate';
*
* 4. 插件方法; eg: 'testPlugin.echoJs';
* 4. 插件模型方法; eg: 'testPlugin.chartUserModel.getInfo';
*/
function ActionApply($action,$args=array()){
static $_cache = array();
if(is_array($action)){ //可调用方法; array($this,'log');
return call_user_func_array($action,$args);
}
if(isset($_cache[$action])){
return call_user_func_array($_cache[$action],$args);
}
if(function_exists($action)){ //全局函数;
$_cache[$action] = $action;
}else{
$arrs = explode('.',$action);
$arrs = is_array($arrs) ? $arrs : array();
$className = substr($action,0,strrpos($action,'.'));
$method = $arrs[count($arrs) - 1];
$obj = Action($className);
if(!$method || !is_object($obj)){
return actionCallError("$action method not exists!");
}
// 类查存在,最后一个不是方法时,默认将第三个参数作为参数; 支持多参数调用方式;
// http://127.0.0.1/kod/kodbox/?test/test/index/page/1/limit/10
if(!method_exists($obj,$method)){
if(!$arrs[2] || !method_exists($obj,$arrs[2])){
return actionCallError("$action method not exists!");
}
$method = $arrs[2];
}
$_cache[$action] = array($obj,$method);
}
return call_user_func_array($_cache[$action], $args);
}
function actionCallError($msg){
return false;
// think_exception($msg,false);
write_log($msg."\n".get_caller_msg(),'error');
return false;
}
/**
* 调用控制器,插件方法,或直接调用函数;
* 参数合并为数组; 类似于js的 call($object,$arg1,$arg2,...);
*
* ActionCall('user.index.appConfig',"add",'123');
* ActionCall('UserModel.count');
*
* ActionCall('chartPlugin.view','5');
* ActionCall('chartPlugin.user.view.list');
* ActionCall('chartPlugin.userModel.list');
*/
function ActionCall($action){
$args = array_slice(func_get_args(),1);
return ActionApply($action,$args);
}
function ActionCallApi($uri,$param='',$allowExec=true){
$paramStr = $param;
if(is_array($param)){
$paramStr = '';
foreach($param as $key => $value){
$value = is_array($value) ? json_encode($value) : $value;
$value = is_bool($value) ? intval($value) : $value;
$paramStr .= '&'.$key.'='.rawurlencode($value);
}
}
$token = Action('user.index')->accessToken();
$uri = str_replace('.','/',$uri).'&accessToken='.$token.$paramStr;
$res = '';
$phpBin = phpBinCommand();
if($allowExec && $phpBin && function_exists('shell_exec')){
$command = $phpBin.' '.BASIC_PATH.'index.php '.escapeshellarg($uri);
$res = shell_exec($command);
}
if(!$res){
$streamContext = stream_context_create(array('http'=>array('timeout'=>20,'method'=>"GET")));
$res = file_get_contents(APP_HOST.'index.php?'.$uri,false,$streamContext);
}
$json = json_decode($res,true);
$result = is_array($json) ? $json:array('code'=>null,'data'=>$res);
if(!$json){echo $res;}
return $result;
}
/**
* 调用控制器,插件方法,或直接调用函数; 拦截show_json退出;返回show_json的内容数组;
*
* 调用方法有多个show_json;默认返回第一个调用的结果;
* : 为避免后续继续执行引起其他问题,需要在前面show_json前加上return (容易出bug,逐步废弃,用ActionCallResult替代)
*/
function ActionCallHook($action){
ob_start();
$args = array_slice(func_get_args(),1);
$GLOBALS['SHOW_JSON_NOT_EXIT'] = 1;
$result = ActionApply($action,$args);
$echo = ob_get_clean();
$result = $echo ? json_decode($echo,true) : $result;// 优先使用输出内容;
$GLOBALS['SHOW_JSON_NOT_EXIT_DONE'] = 0;
$GLOBALS['SHOW_JSON_NOT_EXIT'] = 0;
return $result;
}
/**
* 调用控制器,插件方法,或直接调用函数; 并对show_json输出进行处理;
*/
function ActionCallResult($action,$resultParse){
$args = array_slice(func_get_args(),2);
$GLOBALS['SHOW_JSON_RESULT_PARSE'] = $resultParse;
ActionApply($action,$args);
}
function beforeShutdown(){
Hook::trigger('beforeShutdown');
}
$_SERVER['BASIC_PATH'] = BASIC_PATH;
$_SERVER['LIB_DIR'] = LIB_DIR;
// https://www.jianshu.com/p/1a443d542219;
function beforeShutdownError($code=false,$msg='',$file='',$line=0){
switch ($code) {
case E_PARSE:
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:$errorType = 'Fatal Error';break;
case E_WARNING:
case E_USER_WARNING:
case E_COMPILE_WARNING:
case E_RECOVERABLE_ERROR:$errorType = 'Warning';break;
case E_STRICT:$errorType = 'Strict';break;
case E_NOTICE:
case E_USER_NOTICE:$errorType = 'Notice';break;
case E_DEPRECATED:
case E_USER_DEPRECATED:$errorType = 'Deprecated';break;
default :break;
}
if(!$errorType || $errorType == 'Notice' || $errorType=='Deprecated') return;
$file = '/'.str_replace($_SERVER['BASIC_PATH'],'',$file);
$error = $errorType.','.$msg.','.$file.','.$line;
write_log($error."\n".get_caller_msg(1)."\n".json_encode($GLOBALS['in']),'error');
}
function beforeShutdownFatalError($e){
think_exception($e);
}
$errorLevel = E_ALL^E_NOTICE^E_WARNING^E_DEPRECATED;
register_shutdown_function('beforeShutdown'); // 结束时调用;有exit则不会走到该处;
set_error_handler('beforeShutdownError',$errorLevel); // 错误处理记录;notice,warning,error等都会进入;
if(function_exists('set_exception_handler')){
set_exception_handler('beforeShutdownFatalError'); //
}
stream_wrapper_register('kodio','StreamWrapperIO');