Submitted by gouki on 2008, November 27, 6:26 PM
昨天刚刚解决ZS白屏的问题,再次启动的时候,确实是正常了。。。
然而部份菜单却是方框,查了一些资料,发现是中文字体的问题,于是,将Windows下的宋体(simsun.ttc)拷贝过来,改名为: LucidaSansRegular.ttf,覆盖掉:/usr/local/Zend/ZendStudio-5.5.1/jre/lib/fonts 下的同名文件。
即:
XML/HTML代码
- unlink /usr/local/Zend/ZendStudio-5.5.1/jre/lib/fonts/LucidaSansRegular.ttf
- cp /media/disk/WINDOWS/Fonts/simsun.ttc /usr/local/Zend/ZendStudio-5.5.1/jre/lib/fonts/LucidaSansRegular.ttf
Tags: ubuntu, zend, zendstudio, 方框, 中文
Software | 评论:0
| 阅读:23198
Submitted by gouki on 2008, November 20, 11:31 PM
原文地址:http://www.laruence.com/2008/11/20/630.html
膘叔的話:foreach是PHP語言里最常用的語法結構之一了,只要是數組操作,極大可能是會用到它,自從PHP5之后,它也能操作對象了。自此,foreach的使用率又上升了很多。但是有多少人知道它的背後原理呢?記得在以前的時候,好象是說foreach其實就是while( list )等的封裝。但由于一直沒有看過PHP的源碼也不能這么確定。(PS:如果用dezender等破解軟件破解PHP代碼,那么你會發現,代碼是foreach的那塊,都是被替換成while( list each )這種,所以我才會有上面的猜測)正好,看到風雪之隅有這個介紹,就轉貼一下。自己也可以學習一下。呵呵
foreach是PHP中很常用的一个用作数组循环的控制语句。
因为它的方便和易用,自然也就在后端隐藏着很复杂的具体实现方式(对用户透明)
今天,我们就来一起分析分析,foreach是如何实现数组(对象)的遍历的。
本节内容涉及到较多编译原理(lex and yacc)的知识,所以如果您觉得看不太懂,可以先找相关的资料看看。
我们知道PHP是一个脚本语言,也就是说,用户编写的PHP代码最终都是会被PHP解释器解释执行,
特别的,对于PHP来说,所有的用户编写的PHP代码,都会被翻译成PHP的虚拟机ZE的虚拟指令(OPCODES)来执行(参看:深入理解PHP原理之Opcodes).
不论细节的话,就是说,我们所编写的任何PHP脚本,都会最终被翻译成一条条的指令,从而根据指令,由相应的C编写的函数来执行。
那么foreach会被翻译成什么样子呢?
foreach($arr as $key => $val){
echo $key . '=>' . $val . "\n";
}
在词法分析阶段,foreach会被识别为一个TOKEN:T_FOREACH,
在语法分析阶段,会被规则:
unticked_statement: //没有被绑定ticks的语句
//有省略
| T_FOREACH '(' variable T_AS
{ zend_do_foreach_begin(&$1, &$2, &$3, &$4, 1 TSRMLS_CC); }
foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
| T_FOREACH '(' expr_without_variable T_AS
{ zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); }
variable foreach_optional_arg ')' { zend_check_writable_variable(&$6); zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); }
foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); }
//有省略
;
仔细分析这段语法规则,我们可以发现,对于:
foreach($arr as $key => $val){
echo $key . ‘=>’ . $val .”\n”;
}
会被分析为:
T_FOREACH '(' variable T_AS { zend_do_foreach_begin('foreach', '(', $arr, 'as', 1 TSRMLS_CC); }
foreach_variable foreach_optional_arg(T_DOUBLE_ARROW foreach_variable) ')' { zend_do_foreach_cont('foreach', '(', 'as', $val, ')' TSRMLS_CC); }
foreach_satement {zend_do_foreach_end('foreach', 'as');}
如果你懂语法分析,或者你懂yacc,你会奇怪,为什么zend_do_foreach_cont的$6是$val 而不是 $key呢? 注意另外一个语法规则:
foreach_optional_arg:
/* empty */ { $$.op_type = IS_UNUSED; }
| T_DOUBLE_ARROW foreach_variable { $$ = $2; }
;
也就是说,对于$key => $val的情况,yacc的内容栈对应的foreach_variable会被替换 {$$=$2};
然后,让我们来看看foreach_statement:
它其实就是一个代码块,体现了我们的 echo $key . ‘=>’ . $val .”\n”;
T_ECHO expr;
显然,实现foreach的核心就是如下3个函数:
zend_do_foreach_begin
zend_do_foreach_cont
zend_do_foreach_end
其中,zend_do_foreach_begin (代码太长,直接写伪码) 主要做了:
1. 记录当前的opline行数(为以后跳转而记录)
2. 对数组进行RESET(讲内部指针指向第一个元素)
3. 获取临时变量 ($val)
4. 设置获取变量的OPCODE FE_FETCH,结果存第3步的临时变量
4. 记录获取变量的OPCODES的行数
而对于 zend_do_foreach_cont来说:
1. 根据foreach_variable的u.EA.type来判断是否引用
2. 根据是否引用来调整zend_do_foreach_begin中生成的FE_FETCH方式
3. 根据zend_do_foreach_begin中记录的取变量的OPCODES的行数,来初始化循环(主要处理在循环内部的循环:do_begin_loop)
最后zend_do_foreach_end:
1. 根据zend_do_foreach_begin中记录的行数信息,设置ZEND_JMP OPCODES
2. 根据当前行数,设置循环体下一条opline, 用以跳出循环
3. 结束循环(处理循环内循环:do_end_loop)
4. 清理临时变量
当然, 在zend_do_foreach_cont 和 zend_do_foreach_end之间 会在语法分析阶段被填充foreach_satement的语句代码。
这样,就实现了foreach的OPCODES line。
比如对于我们开头的实例代码,最终生成的OPCODES是:
filename: /home/huixinchen/foreach.php
function name: (null)
number of ops: 17
compiled vars: !0 = $arr, !1 = $key, !2 = $val
line # op fetch ext return operands
-------------------------------------------------------------------------------
2 0 SEND_VAL 1
1 SEND_VAL 100
2 DO_FCALL 2 'range'
3 ASSIGN !0, $0
3 4 FE_RESET $2 !0, ->14
5 FE_FETCH $3 $2, ->14
6 ZEND_OP_DATA ~5
7 ASSIGN !2, $3
8 ASSIGN !1, ~5
4 9 CONCAT ~7 !1, '-'
10 CONCAT ~8 ~7, !2
11 CONCAT ~9 ~8, '%0A'
12 ECHO ~9
5 13 JMP ->5
14 SWITCH_FREE $2
7 15 RETURN 1
16* ZEND_HANDLE_EXCEPTION
我们注意到FE_FETCH的op2的操作数是14,也就是JMP后一条opline,也就是说,在获取完最后一个数组元素以后,FE_FETCH失败的情况下,会跳到第14行opline,从而实现了循环的结束。
而15行opline的op1的操作数是指向了FE_FETCH,也就是无条件跳转到第5行opline,从而实现了循环。
附录:
void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, znode *array, znode *as_token, int variable TSRMLS_DC)
{
zend_op *opline;
zend_bool is_variable;
zend_bool push_container = 0;
zend_op dummy_opline;
if (variable) {
//是否是匿名数组
if (zend_is_function_or_method_call(array)) {
//是否是函数返回值
is_variable = 0;
} else {
is_variable = 1;
}
/* 使用括号记录FE_RESET的opline行数 */
open_brackets_token->u.opline_num = get_next_op_number(CG(active_op_array));
zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); //获取数组/对象和zend_do_begin_variable_parse对应
if (CG(active_op_array)->last > 0 &&
CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_FETCH_OBJ_W) {
/* Only lock the container if we are fetching from a real container and not $this */
if (CG(active_op_array)->opcodes[CG(active_op_array)->last-1].op1.op_type == IS_VAR) {
CG(active_op_array)->opcodes[CG(active_op_array)->last-1].extended_value |= ZEND_FETCH_ADD_LOCK;
push_container = 1;
}
}
} else {
is_variable = 0;
open_brackets_token->u.opline_num = get_next_op_number(CG(active_op_array));
}
foreach_token->u.opline_num = get_next_op_number(CG(active_op_array)); //记录数组Reset Opline number
opline = get_next_op(CG(active_op_array) TSRMLS_CC); //生成Reset数组Opcode
opline->opcode = ZEND_FE_RESET;
opline->result.op_type = IS_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->op1 = *array;
SET_UNUSED(opline->op2);
opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0;
dummy_opline.result = opline->result;
if (push_container) {
dummy_opline.op1 = CG(active_op_array)->opcodes[CG(active_op_array)->last-2].op1;
} else {
znode tmp;
tmp.op_type = IS_UNUSED;
dummy_opline.op1 = tmp;
}
zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
as_token->u.opline_num = get_next_op_number(CG(active_op_array)); //记录循环起始点
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_FE_FETCH;
opline->result.op_type = IS_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->op1 = dummy_opline.result; //被操作数组
opline->extended_value = 0;
SET_UNUSED(opline->op2);
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_OP_DATA; //当使用key的时候附属操作数,当foreach中不包含key时忽略
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
SET_UNUSED(opline->result);
}
void zend_do_foreach_end(znode *foreach_token, znode *as_token TSRMLS_DC)
{
zend_op *container_ptr;
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); //生成JMP opcode
opline->opcode = ZEND_JMP;
opline->op1.u.opline_num = as_token->u.opline_num; //设置JMP到FE_FETCH opline行
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
CG(active_op_array)->opcodes[foreach_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); //设置跳出循环的opline行
CG(active_op_array)->opcodes[as_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); //同上
do_end_loop(as_token->u.opline_num, 1 TSRMLS_CC); //为循环嵌套而设置
zend_stack_top(&CG(foreach_copy_stack), (void **) &container_ptr);
generate_free_foreach_copy(container_ptr TSRMLS_CC);
zend_stack_del_top(&CG(foreach_copy_stack));
DEC_BPC(CG(active_op_array)); //为PHP interactive模式而设置
}
Tags: foreach, php, zend, while, 深入
PHP | 评论:1
| 阅读:25701
Submitted by gouki on 2008, November 7, 11:35 AM
图片附件(缩略图):
图片附件(缩略图):
Tags: zend, phpchina
Software | 评论:1
| 阅读:21666
Submitted by gouki on 2008, August 19, 11:20 PM
原文地址:http://devzone.zend.com/article/3509-Zend_Acl-and-MVC-Integration-Part-I-Basic-Use
原文内容:
By Aldemar Bernal
So, what is wrong with Zend_Acl and the current MVC implementation in the Zend Framework? there is nothing wrong, it is just that it gets not too obvious for developers how to achieve an optimal integration between these two important parts of the framework.
First at all, this article is based on the following Zend Framework Proporsal (link), by this moment this proposal is in Pending Recommendation state.
Well, how it works? There are two key components in this proposal:
- A Front Controller Plugin: This component resolves if the current user has access to the page which is being opened.
- An Action Helper: This component allows you to check whether the current user has access inside a controller.
Based on these two components, let's try them with an example. Let's talk about a website like DevZone, we would need a controller that work with the user management and another one which will deal with article management, as well we need 3 types of users (roles), one for guests, one for writers and another one which will approve the articles; resuming, we have:
Resources:
- user controller.
- article controller.
Roles:
- Guest.
- Writer.
- Admin.
Setting up the Zend_Acl component
After defined what we want to do, the next step will create a Zend_Acl instance which will reflect our model.
/** Creating the ACL object */
require_once 'Zend/Acl.php';
$myAcl = new Zend_Acl();
Creating the roles
Now we create the roles in our Zend_Acl instance.
/** Creating Roles */
require_once 'Zend/Acl/Role.php';
$myAcl->addRole(new Zend_Acl_Role('guest'))
->addRole(new Zend_Acl_Role('writer'), 'guest')
->addRole(new Zend_Acl_Role('admin'), 'writer');
Creating the resources
And then we create the resources needed (one per controller) and their relationship with the roles we created.
/** Creating resources */
require_once 'Zend/Acl/Resource.php';
$myAcl->add(new Zend_Acl_Resource('user'))
->add(new Zend_Acl_Resource('article'));
Creating the permissions
Now that we added the roles and resources to our Zend_Acl instance, it's time to explain what actions must be available to which roles.
- Guest won't have access to edit, add or approve an article.
- Writer won't have access to approve an article.
- Admin will have complete access.
/** Creating permissions */
$myAcl->allow('guest', 'user')
->deny('guest', 'article')
->allow('guest', 'article', 'view')
->allow('writer', 'article', array('add', 'edit'))
->allow('admin', 'article', 'approve');
Creating the access denied view file
We will need to create a view and an action which will address all those denied users, in order to do it, first we create a new action in our error controller:
class ErrorController extends Zend_Controller_Action
{
....
public function deniedAction()
{
}
....
}
And then we create our view file (/application/views/scripts/error/denied.phtml) with some warning message:
<h1>Error</h1>
<h2>Access denied</h2>
<p>You are trying to access an area which you have not allowed.</p>
Finishing the configuration
Okay, we have setup our Zend_Acl configuration, so far, it doesn't look like something new, but the next step is register the controller plugin, this important part takes the Zend_Acl instance we created and then validates it against the current page being accessed by an user.
/** Setting up the front controller */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('path/to/controllers');
/** Registering the Plugin object */
require_once 'Zend/Controller/Plugin/Acl.php';
$aclPlugin = new Zend_Controller_Plugin_Acl($myAcl);
$aclPlugin->setRoleName($currentUserRole);
$front->registerPlugin(new Zend_Controller_Plugin_Acl($acl, 'guest'));
/** Dispatching the front controller */
$front->dispatch();
After this configuration is done, once an user enters in our application, depending the role he/she has the page will be displayed or an access denied page will be displayed.
For more information about this you can go to:
Zend_Acl & MVC Integration
and here is a small implementation source code of this:
Source Code
————END————
由于本文并没有什么特别的地方,而且单词也没有什么,故不作翻译。
Tags: framework, zend, mvc, zend_acl
PHP Framework | 评论:0
| 阅读:24788
Submitted by gouki on 2008, February 17, 3:00 PM
提起Zend,那是在PHP界是相当的有名啊。如果说使用PHP的人居然连Zend也不知道,那是白活了。呵呵
ZendFramework是Zend公司自己推出的一个框架,开发人员都是些元老级人物(但也是有BUG的。。自我安慰一下,高手也会产生BUG),ZF在经历了很长一段时间的发展(大约一年左右吧),才推出1.0系列,现在的版本当然又有了更新
» 阅读全文
Tags: zf, zend, framework
PHP Framework | 评论:0
| 阅读:32783