用Php扩展实现的简单框架 - 5
来源:互联网 发布:中国单挑全世界知乎 编辑:程序博客网 时间:2024/06/05 18:51
/** k_len可为0。 */
static inline zval * kiss_get_cache_obj(char * key, uint k_len TSRMLS_DC) {
zval ** obj;
if(!key) return NULL;
if(!k_len) k_len = strlen(key);
if(SUCCESS==zend_hash_find(Z_ARRVAL_P(KISS_G(obj_cache)), key, k_len+1, (void**)&obj)) {
return *obj;
}
return NULL;
}
static inline void kiss_set_cache_obj(char * key, zval * obj TSRMLS_DC) {
if(!key) return;
add_assoc_zval(KISS_G(obj_cache), key, obj);
}
static inline zend_bool kiss_is_ls_called(char * ls, ulong type TSRMLS_DC) {
char * key;
uint k_len;
zend_bool ret;
if(!ls) return 0;
k_len = spprintf(&key, 0, "%s->%s", ls, ls_func_name(type));
ret = zend_hash_exists(Z_ARRVAL_P(KISS_G(ls_called)), key, k_len+1);
efree(key);
return ret;
}
static inline void kiss_set_ls_called(char * ls, ulong type TSRMLS_DC) {
char * key;
if(!ls) return;
spprintf(&key, 0, "%s->%s", ls, ls_func_name(type));
add_assoc_long(KISS_G(ls_called), key, 1);
efree(key);
}
/** 根据[模块名和]控制器合成控制器类名。
* 控制器为空则返回0。 */
static uint kiss_make_class_name(char * mdl, char * ctl, char ** cls_name TSRMLS_DC) {
char fm, fc;
uint cls_len;
kiss_status * status = KISS_G(status);
if(!ctl || '/0'==*ctl) return 0;
fc = ctl[0];
if('a' <= fc && 'z' >= fc) fc -= 32;
if(!status->prefix_ctl || !mdl || '/0'==*mdl) { // 不使用模块作为类名前缀(或缺省模块)
cls_len = spprintf(cls_name, 0, "%c%s%s", fc, ctl+1, status->postfix_ctl);
} else {
fm = mdl[0];
if('a' <= fm && 'z' >= fm) fm -= 32;
cls_len = spprintf(cls_name, 0, "%c%s%c%s%s", fm, mdl+1, fc, ctl+1, status->postfix_ctl);
}
return cls_len;
}
/** 根据[控制器路径和]控制器合成控制器类名。
* 控制器为空则返回NULL。
* TODO: ctl_dir为空时使用DOC_ROOT或缺省模块路径? */
static char * kiss_make_class_file(char * ctl_dir, char * ctl TSRMLS_DC) {
char fc, * cls_file;
kiss_status * status = KISS_G(status);
if(!ctl || '/0'==*ctl) return NULL;
fc = ctl[0];
if('a' <= fc && 'z' >= fc) fc -= 32;
if(!ctl_dir || '/0'==*ctl_dir) {
spprintf(&cls_file, 0, "%c%s%s%s", fc, ctl+1, status->postfix_ctl, status->ext_proc);
} else {
spprintf(&cls_file, 0, "%s%c%s%s%s", ctl_dir, fc, ctl+1, status->postfix_ctl, status->ext_proc);
}
return cls_file;
}
/** NULL或""参数,或文件不存在或不可读则返回0。
* TODO: 加强文件读取部分(error, eof, empty line ...)。 */
static zend_bool kiss_init_cfg(char * cfg_file TSRMLS_DC) {
FILE * stream;
char key[1024], value[1024], dir_sep;
uint k_len, v_len;
kiss_rule * rule;
// char line[1024];
if(!cfg_file || '/0'==*cfg_file) return 0;
stream = fopen(cfg_file, "r");
if(!stream) return 0;
dir_sep = KISS_G(dir_sep);
while(!feof(stream)) {
// fread(line, 1, 1024, stream);
if(EOF == fscanf(stream, "%s %s", key, value)) continue;
if(ferror(stream)) { break; }
k_len = strlen(key) - 1;
while(k_len>0 && key[k_len] == PATH_SEP) k_len--;
key[++k_len] = '/0';
v_len = strlen(value);
if(value[v_len-1] != dir_sep) {
value[v_len] = dir_sep;
value[++v_len] = '/0';
}
if(!strncmp(key, LS_PREFIX, 2)) {
zend_hash_update(&KISS_G(hosts_ls), key, k_len+1,
(void *)pestrdup(value, 1), v_len+1, NULL);
continue;
} else if(!strncmp(key, RW_PREFIX, 2)) {
rule = kiss_make_rule_value(value, v_len);
if(!rule) continue;
zend_hash_update(&KISS_G(hosts_rw), key, k_len+1,
(void *)rule, sizeof(kiss_rule), NULL);
efree(rule);
}
}
fclose(stream);
KISS_G(cfg_inited) = 1;
return 1;
}
/** 分层的路由器,也解析uri中的查询参数。返回值:是否匹配URI。 */
static zend_bool kiss_route_layer(char * path TSRMLS_DC) {
kiss_request * req;
kiss_status * status;
char * domain, * p1, * p2, * prev=NULL, * key=NULL, * rule_key;
uint dm_len, p1_len, rule_key_len, ep_len;
if(!path || '/0'==*path) return 0;
req = KISS_G(request);
status = KISS_G(status);
domain = req->host;
dm_len = strlen(domain);
p1_len = strlen(path);
if(status->ext_path) { // 过滤
ep_len = strlen(status->ext_path);
if(strcmp(path+p1_len-ep_len, status->ext_path))
return 0;
else
p1_len -= ep_len;
}
p1 = (char*)emalloc(p1_len+2);
if(!p1) return 0;
strncpy(p1, path, p1_len);
*(p1 + p1_len) = '/';
*(p1 + p1_len + 1) = '/0';
p2 = p1;
while(*p2) {
if('/' != *p2) {
if(!prev) prev = p2;
} else {
*p2 = '/0';
if(prev) {
if(!req->module) { // 模块优先于缺省模块中的同名控制器
rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", domain, prev);
if(!zend_hash_exists(&KISS_G(hosts_rw), rule_key, rule_key_len+1)) {
efree(p1);
efree(rule_key);
return 0;
}
req->module = estrdup(prev);
efree(rule_key);
} else if(!req->controller) {
req->controller = estrdup(prev);
} else if(!req->action) {
req->action = estrdup(prev);
} else {
if(key) {
add_assoc_string(req->query, key, prev, 1);
key = NULL;
} else {
key = prev;
}
}
prev = NULL;
}
}
p2 ++;
}
if(key) {
add_assoc_string(req->query, key, "", 1);
key = NULL;
}
if(!req->module) req->module = estrdup(status->default_mdl);
if(!req->controller) req->controller = estrdup(status->default_ctl);
if(!req->action) req->action = estrdup(status->default_act);
efree(p1);
return 1;
}
/** 分发器:对象方法(默认)或函数(过程)。 */
static inline zend_bool kiss_dispatch(TSRMLS_D) {
// if(KISS_DISPATCH_METHOD == KISS_G(dispatch_type))
if(KISS_DISPATCH_METHOD == KISS_G(status)->dispatch_type)
return kiss_dispatch_method(TSRMLS_C);
else
return kiss_dispatch_function(TSRMLS_C);
}
/** 对象方法分发器。
* 可能抛出异常(类文件或类无效)。 */
static zend_bool kiss_dispatch_method(TSRMLS_D) {
char * ctl_file, * func_name, * cls_name, * rule_key, * ctl_dir, * ctl_dir_abs;
uint rule_key_len, cls_len;
zend_bool flag;
zval * ctl, * func, * ret, * ins;
kiss_request * req;
kiss_rule * rule;
req = KISS_G(request);
cls_len = kiss_make_class_name(req->module, req->controller, &cls_name TSRMLS_CC);
if(!cls_len) return 0;
ins = kiss_get_cache_obj(cls_name, cls_len TSRMLS_CC);
if(!ins) {
rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", req->host, req->module);
if(zend_hash_find(&KISS_G(hosts_rw), rule_key, rule_key_len+1, (void**)&rule) == FAILURE) {
efree(rule_key);
efree(cls_name);
return 0;
}
ctl_dir = rule->controller_dir;
efree(rule_key);
if(!kiss_class_exists(cls_name TSRMLS_CC)) {
if(kiss_absolute_path(ctl_dir, &ctl_dir_abs TSRMLS_CC)) {
ctl_file = kiss_make_class_file(ctl_dir, req->controller TSRMLS_CC);
} else {
ctl_file = kiss_make_class_file(ctl_dir_abs, req->controller TSRMLS_CC);
efree(ctl_dir_abs);
}
if(!ctl_file) { efree(cls_name); return 0; }
MAKE_STD_ZVAL(ctl);
ZVAL_STRING(ctl, ctl_file, 0);
flag = kiss_eval(KISS_REQUIRE_ONCE, ctl, NULL TSRMLS_CC);
// efree(ctl_file);
zval_ptr_dtor(&ctl);
if(!flag) {
zend_throw_exception_ex(NULL, KISS_E_CLSFILE TSRMLS_CC, "找不到类<b>%s</b>的定义文件!", cls_name);
efree(cls_name);
return 0;
}
}
ins = kiss_create_object(cls_name TSRMLS_CC);
if(!ins || !IS_ZEND_STD_OBJECT(*ins)
#ifndef PHP_WIN32
|| !instanceof_function(Z_OBJCE_P(ins), KISS_G(action_ce) TSRMLS_CC)
#endif
) {
zend_throw_exception_ex(NULL, KISS_E_INSTANCE TSRMLS_CC, "未能正确创建类%s的实例!", cls_name);
efree(cls_name);
if(ins) zval_ptr_dtor(&ins);
return 0;
}
kiss_set_cache_obj(cls_name, ins TSRMLS_CC);
/*
MAKE_STD_ZVAL(func);
MAKE_STD_ZVAL(ret);
ZVAL_STRING(func, KISS_ACTION_INIT_FUNC, 0);
if(FAILURE == kiss_call_user_function(NULL, &ins, func, ret, 0, NULL TSRMLS_CC)) {
zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC,
"调用方法%s::" KISS_ACTION_INIT_FUNC "()失败!", cls_name);
zval_ptr_dtor(&ret);
efree(func);
efree(cls_name);
return 0;
}
} else {
MAKE_STD_ZVAL(func);
MAKE_STD_ZVAL(ret);
}
*/
}
MAKE_STD_ZVAL(func);
MAKE_STD_ZVAL(ret);
if(!kiss_ls_dispatch(KISS_LS_PRE_DISPATCH TSRMLS_CC)) {
//zval_ptr_dtor(&func); // 有内存泄露
zval_ptr_dtor(&ret);
efree(func); // func为zval*,但其strval非拷贝的,不可用zval_ptr_dtor()。
efree(cls_name);
return 0;
}
spprintf(&func_name, 0, "%s%s", req->action, KISS_G(status)->postfix_act);
ZVAL_STRING(func, func_name, 0);
if(FAILURE == kiss_call_user_function(NULL, &ins, func, ret, 0, NULL TSRMLS_CC)) {
zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC, "调用方法%s::%s()失败!", cls_name, func_name);
zval_ptr_dtor(&ret);
efree(func); // func为zval*,但其strval非拷贝的,不可用zval_ptr_dtor()。
efree(cls_name);
return 0;
}
efree(cls_name);
// zval_ptr_dtor(&ins);
// efree(func_name);
zval_ptr_dtor(&func);
zval_ptr_dtor(&ret);
if(!kiss_ls_dispatch(KISS_LS_POST_DISPATCH TSRMLS_CC)) return 0;
return 1;
}
/** 函数分发器。TODO: 修正、完善。 */
static zend_bool kiss_dispatch_function(TSRMLS_D) {
zval * ctl, * func, * ret;
char * root, * ctl_file, * func_name, * rule_key, * ctl_dir;
uint rule_key_len;
kiss_request * req;
kiss_rule * rule;
req = KISS_G(request);
rule_key_len = spprintf(&rule_key, 0, RW_PREFIX ":%s/%s", req->host, req->module);
if(zend_hash_find(&KISS_G(hosts_rw), rule_key, rule_key_len+1, (void**)&rule) == FAILURE) {
efree(rule_key);
return 0;
}
ctl_dir = rule->controller_dir;
efree(rule_key);
if(IS_ABSOLUTE_PATH(ctl_dir, strlen(ctl_dir))) {
spprintf(&ctl_file, 0, "%s%s" PHP_EXT, ctl_dir, req->controller);
} else {
root = zend_getenv(DOC_ROOT, DOC_ROOT_LEN TSRMLS_CC);
if(!root || '/0'==*root) root = KISS_G(status)->cli_root;
if(root) spprintf(&ctl_file, 0, "%s%s%s%s" PHP_EXT, root, KISS_G(dir_sep), ctl_dir, req->controller);
spprintf(&ctl_file, 0, "%s%c%s%s" PHP_EXT, root, KISS_G(dir_sep), ctl_dir, req->controller);
}
MAKE_STD_ZVAL(ctl);
ZVAL_STRING(ctl, ctl_file, 0);
kiss_eval(KISS_REQUIRE_ONCE, ctl, NULL TSRMLS_CC);
// 无文件则报错,需要抑制,以避免显示目录结构。
MAKE_STD_ZVAL(func);
spprintf(&func_name, 0, "%s" ACTION_EXT, req->action);
ZVAL_STRING(func, func_name, 0);
MAKE_STD_ZVAL(ret);
if(FAILURE == kiss_call_user_function(EG(function_table), NULL, func, ret, 0, NULL TSRMLS_CC)) {
//如何区分不同控制器中的同名函数???
php_printf("failure to call function: %s<br/>/n", req->action);
}
// efree(ctl_file);
zval_ptr_dtor(&ctl);
// efree(func_name);
zval_ptr_dtor(&func);
zval_ptr_dtor(&ret);
return 1;
}
/** TODO: 整理代码。
* 可能抛出异常(类文件或类无效)。 */
static zend_bool kiss_ls_dispatch(ulong type TSRMLS_DC) {
char * ls_key, * ls_dir = NULL, * ls_dir_abs = NULL, * ls, * ls_file;
char * func_name;
uint ls_key_len, ls_size, ls_file_len;
zend_bool flag, exe_flag = 1;
zval * lss, * ls_file2, * disp_func, * ret, * ls_ins;
kiss_request * req;
kiss_status * status;
HashPosition pos_ht;
req = KISS_G(request);
status = KISS_G(status);
func_name = ls_func_name(type);
ls_key_len = spprintf(&ls_key, 0, LS_PREFIX ":%s", req->host);
if(zend_hash_find(&KISS_G(hosts_ls), ls_key, ls_key_len+1, (void**)&ls_dir)==SUCCESS) {
lss = kiss_get_listeners(type TSRMLS_CC);
if(lss && zend_hash_num_elements(Z_ARRVAL_P(lss))) {
if(!kiss_absolute_path(ls_dir, &ls_dir_abs TSRMLS_CC)) ls_dir = ls_dir_abs;
for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(lss), &pos_ht);
zend_hash_get_current_key_ex(Z_ARRVAL_P(lss), &ls, &ls_size,
NULL, 0, &pos_ht)==HASH_KEY_IS_STRING;
zend_hash_move_forward_ex(Z_ARRVAL_P(lss), &pos_ht)) {
if(kiss_is_ls_called(ls, type TSRMLS_CC)) continue;
ls_ins = kiss_get_cache_obj(ls, ls_size-1 TSRMLS_CC);
if(!ls_ins) {
if(!kiss_class_exists(ls TSRMLS_CC)) {
ls_file_len = spprintf(&ls_file, 0, "%s%s%s", ls_dir, ls, status->ext_proc);
MAKE_STD_ZVAL(ls_file2);
ZVAL_STRINGL(ls_file2, ls_file, ls_file_len, 0);
flag = kiss_eval(KISS_REQUIRE_ONCE, ls_file2, NULL TSRMLS_CC);
zval_ptr_dtor(&ls_file2);
if(!flag) {
zend_throw_exception_ex(NULL, KISS_E_CLSFILE TSRMLS_CC, "找不到类<b>%s</b>的定义文件!", ls);
efree(ls_key);
efree(ls);
if(ls_dir_abs) efree(ls_dir_abs);
return 0;
}
}
ls_ins = kiss_create_object(ls TSRMLS_CC);
if(!ls_ins || !IS_ZEND_STD_OBJECT(*ls_ins)
#ifndef PHP_WIN32
|| !instanceof_function(Z_OBJCE_P(ls_ins), KISS_G(listener_ce) TSRMLS_CC)
#endif
) {
zend_throw_exception_ex(NULL, KISS_E_INSTANCE TSRMLS_CC, "未能正确创建类%s的实例!", ls);
efree(ls_key);
efree(ls);
if(ls_ins) {
// zval_ptr_dtor(&ls_ins);
zval_ptr_dtor(&lss);
}
return 0;
}
kiss_set_cache_obj(ls, ls_ins TSRMLS_CC);
}
MAKE_STD_ZVAL(disp_func);
ZVAL_STRING(disp_func, func_name, 1);
MAKE_STD_ZVAL(ret);
if(FAILURE==kiss_call_user_function
(NULL, &ls_ins, disp_func, ret, 0, NULL TSRMLS_CC)) {
zend_throw_exception_ex(NULL, KISS_E_CALLMTD TSRMLS_CC, "调用方法%s::%s()失败!", ls, func_name);
exe_flag = 0; // 避免重复调用释放内存的代码
}
kiss_set_ls_called(ls, type TSRMLS_CC);
zval_ptr_dtor(&disp_func);
zval_ptr_dtor(&ret);
// zval_ptr_dtor(&ls_ins);
}
}
if(lss) zval_ptr_dtor(&lss);
// efree(ls_dir);
}
efree(ls_key);
if(ls_dir_abs) efree(ls_dir_abs);
return exe_flag;
}
/** 根据传入的类型,获得当前action的监听器。 */
static zval * kiss_get_listeners(ulong type TSRMLS_DC) {
zval * ls, * ret, ** value;
kiss_request * req;
ls = KISS_LS_PRE_DISPATCH==type ?
KISS_G(ls_pre_disp) : KISS_G(ls_post_disp);
if(!ls) return NULL;
req = KISS_G(request);
if(zend_hash_find(Z_ARRVAL_P(ls), req->module,
strlen(req->module)+1, (void**)&value)==FAILURE) {
return NULL;
}
ls = *value;
if(zend_hash_find(Z_ARRVAL_P(ls), req->controller,
strlen(req->controller)+1, (void**)&value)==FAILURE) {
return NULL;
}
ls = *value;
MAKE_STD_ZVAL(ret);
array_init(ret);
if(zend_hash_find(Z_ARRVAL_P(ls), "", 1, (void**)&value)==SUCCESS) {
php_array_merge(Z_ARRVAL_P(ret), Z_ARRVAL_PP(value), 0 TSRMLS_CC);
}
if(zend_hash_find(Z_ARRVAL_P(ls), req->action,
strlen(req->action)+1, (void**)&value)==SUCCESS) {
php_array_merge(Z_ARRVAL_P(ret), Z_ARRVAL_PP(value), 0 TSRMLS_CC);
}
return ret;
}
#endif // PHP_KISS_INNER_C
- 用Php扩展实现的简单框架 - 5
- PHP扩展实现的简单MVC框架
- 用Php扩展实现的简单框架1
- 用Php扩展实现的简单框架 - 3
- 用Php扩展实现的简单框架 - 4
- 用Php扩展实现的简单框架 - 6 - 使用示例
- 用Php扩展实现的简单框架 - 7 - v0.2
- PHP扩展开发-写一个简单的框架
- PHP MVC 框架的简单实现参考
- php实现MVC框架的简单实例
- PHP的MVC框架简单实现
- werkzeug实现简单Python web框架(5):扩展思路
- 一个简单的PHP扩展
- php实现的一个简单json rpc框架实例
- PHP的扩展框架之Phalcon初探
- 【php框架学习】最简单的php mvc 模型框架实现
- php 框架扩展类
- PHP 开发框架扩展
- 用Php扩展实现的简单框架 - 4
- 2.5 限定符(3)
- .NET中如何在调用COM的时候得到返回参数值 (转)
- 根据excel或者doc模板生成excel和doc文档
- 最简单的ajax应用
- 用Php扩展实现的简单框架 - 5
- 用Php扩展实现的简单框架 - 6 - 使用示例
- 2.5 限定符 (2)
- 用Php扩展实现的简单框架 - 7 - v0.2
- 反射技术动态调用方法中的引用类型参数传递 (转)
- 2.5 限定符(1)
- 2.4 反义
- 那些不能在一起吃的水果搭配
- 自己实现的栈 用数组实现