php中文手册的两处错误

以下错误和遗漏大多来自网友的提问,然后回答时从手册中发现的几个问题。
1.抽象类翻译。错误。
在语言参考→类与对象→抽象类一节的开头,有这样的描述"抽象类中 至少要包含一个抽象方法。"(http://www.php.net/manual/zh/language.oop5.abstract.php) .很明显,这是错误的,因为可以定义空的抽象类,也可以定义包含非抽象方法的抽象类。
英文原文是“any class that contains at least one abstract method must also be abstract. ”(http://www.php.net/manual/en/language.oop5.abstract.php)。翻译过来就是“任何含有抽象方法的类必须定义为抽象类”。这跟之前的描述完全是两码事,中文手册的翻译属于典型的翻译错误。

2.日期函数date的z参数。错误。
http://cn.php.net/manual/en/function.date.php
英文“z the day of the year (starting from 0) 0 through 365
中文手册:“z  年份中的第几天   0到366”(http://cn.php.net/manual/zh/function.date.php


。。另外,还有很多函数遗漏了一些重要的注意事项或版本信息,不过很多都已在最新版手册中得到了修正。以及部分翻译晦涩的地方。以上问题大多已反馈。如果有遇到类似困惑的地方,先首先看下是不是你看的中文手册有误。

php里的继父类和义父类

      注:本文非技术文章。
     什么叫继父类:在php里,父类就是父类,子类就是子类,二者都属于人(这不废话么~这就是弱类型的概念),虽有继承关系,但没有血缘关系,无法在需要时进行合体(转型)。因此,PHP里的父类也叫继父类,当然了,子类就叫继子类。这是什么意思呢,也就是说,像C,JAVA里这样的转型语法 father *pf=new son; 是不存在的。这就是典型的多态特征。对于没有转型概念的php而言,也就没有了类型的界定,“同一类型”也无从谈起,子类和父类被生生的割裂了,子类就是子类,父类就是父类,是两个完全不同的类型,无法互转。当然,你硬要说两者都是同一种类型-弱类型,也不是不可。这也是你可以说PHP有多态,也可以说无多态的一个原因。
     什么叫义父类:stdClass是一个保留类,类似JAVA里的OBJECT,但是这个类并不是PHP里其他类的基类,和object又不一样,但这个类又能被继承,而且还能把其它类型的数据转换成这个类。如果把一个标量转为object类型,那么就是转成它了。我不承认我和你有任何瓜葛,但是你要是无路可走,叫我声义父,我就能收留你。因此此类又叫义父类。
   继父和义父有啥区别呢?继父抚养继子,有被继承权;而义父只是单纯的收留而已。
    (*^__^*) 嘻嘻……

php的exec函数在linux下返回值不能为负数的问题

l来自雪候鸟的文章:http://www.laruence.com/2012/02/01/2503.html,正好解释了这个问题。
原问题来自这里
http://bbs.phpchina.com/thread-230760-1-1.html
string exec ( string $command [, array &$output [, int &$return_var ]] )

第三个参数, 怎么不能接收负数??
这里的&$return_var就是程序返回值,起初我的回答是可以为负数。
一般在C语言里我们会这样写
#include <stdio.h>
#include <stdlib.h>
int main()
{
    printf("^_^\n");
    return -5;
}
这个-5就是返回值,但习惯上是写成0或者1的。
注意:很多人的C代码里把main函数写成 void main() 这样实际上是不对的,详细的就不说了。
把上面的代码编译后,到CMD下运行,然后就能看到输出结果了。接着,输入“echo %ERRORLEVEL%”,回车,就可以看到程序的返回值了。这个%ERRORLEVEL%就代表了程序的返回状态。在WIN下确实是可以为负数的。如图所示:
exec_return_win.png
,php调用也是正常的。
E:\dev\php535>php -r "exec('return.exe',$out,$a);var_dump($a);"
int(-2)
但是到了linux下,始终为正数,刚开始怀疑是权限问题,用了chmod +x后,排除了权限问题。
exec("/home/wwwroot/test/rtest.out 2>&1",$out,$a);
var_dump($out,$a);
array(1) { [0]=> string(3) "^_^" } int(251)
看起来成了256+return val,可以看到实际上返回了负数,只不过被转换成正数了。
接着看了下standard/exec.c里的源代码,没发现啥端倪,干到很奇怪,突然想到自己忘了一步。忘了看程序返回给OS的值了.
可以使用echo $? 显示最后命令的推出状况。
-bash-3.00$ vi main.c
-bash-3.00$ gcc -o ./mm main.c
-bash-3.00$ ll
total 48
drwxr-xr-x  3 www www 4096 May  4  2011 2011
drwxr-xr-x  6 www www 4096 Jun 23  2011 eoc
-rwxr-xr-x  1 www www 7131 Feb  1 12:47 hello
-rw-r--r--  1 www www    3 Feb  1 12:51 hello.c
-rw-r--r--  1 www www   99 Feb  1 12:50 main.c
-rwxr-xr-x  1 www www 4714 Feb  1 12:51 mm
drwxr-xr-x  3 www www 4096 Jun 24  2011 test
-bash-3.00$ ./mm
^_^
-bash-3.00$ echo $?
251
-bash-3.00$
这样就可以看看exec返换给OS的值是多少。
在linux下,这个返回值就是无符号类型,返回的是一个正数,所以传给php也是正数了,php实际上也是调用的exec所返回的值。

     OUT了,也许linux就是这么规定的,程序中泰返回值为1~255区间,而自己不清楚这个规则。不过还没有确定是否linux里就是这么规定的。虽然问题很蛋疼,意义不大,不过也可以在这里留给遇到类似问题的人参考。不过到这里也没深究的必要了。谁要是真想彻底搞清楚,可以看看shell这块

php中的异常机制详解(2)

    在上一节,提到php只有在用if-else进行判断抛出异常后才能捕获异常,或者是有内建的异常机制时,会先触发错误,再捕获异常。
    那php里的异常应该怎么用?在什么时候抛异常,什么时候捕获呢?什么场景下能应用异常?
    在下面三种场景下会用到异常处理机制:
    (1)对程序的悲观预测
     如果一个程序员对自己的代码带有“悲观情绪”,这里并不是指该程序员代码质量不高。他认为自己的代码无法一一处理各种可预见的不可预见的情况,那该程序员就会进行异常处理。假设一个场景,程序员悲观地认为自己的这段代码在高并发条件下可能产生死锁,那么他就会悲观地抛出异常,然后在死锁时进行捕获,对异常进行细致的处理。
    (2)程序的需要和对业务的关注
    如果程序员希望业务代码中不会充斥大堆的打印,调试等处理,通常他们会使用异常机制;或者业务上需要定义一些自己的异常,这个时候就需要自定义一个异常, 来对现实世界中各种各样的业务进行补充。比如上班迟到,这种情况,我就认为是一个异常,要收集起来,到月底集中处理,扣你工资;如果程序员希望有预见性地处理可能发生的会影响正常业务的代码,那么它需要异常。在这里,强调了异常是业务处理中必不可少的环节,不能对异常视而不见。异常机制认为,数据一致很重要,在数据一致性可能被破坏时,就需要异常机制来进行预先补救。
    举个例子,比如有个上传文件的业务需求,要把上传的文件保存在一个目录里,并在数据库里插入这个文件的记录,那么这两步就是互相关联密不可分的一个集成的业务,缺一不可。文件保存失败,而插入记录成功就会导致无法下载文件;而文件保存成功数据库写入失败,则会导致没有记录的文件成为死文件,永远得不到下载。
      那么我们假设文件保存成功后没有提示,但是保存失败会自动抛出异常,访问数据库也一样,插入成功没有提示,失败则自动抛出异常,我们就可以把这两个有可能抛出异常的代码段包在一个try语句里,然后在catch捕捉错误,在catch代码段里删除没有被记录到数据库的文件或者删除没有文件的记录,以保证业务数据的一致性。     因此,从业务这个角度讲,异常偏重于保护业务数据一致性,并且强调了对异常业务的处理。
      如果我们的代码中,只是象征性的try-catch,最后打印一个报错,over。这样的异常,不如不用,没有体现了异常的思想。所以,合理的代码应该如下:
<?php
try{
//可能出错的代码段
if(文件上传不成功) throw(上传异常);
if(插入数据库不成功) throw(数据库操作异常);}catch(异常){
必须的补救措施,如删除文件,删除数据库插入记录,这个处理很细致
}
//....
?>

也可以如下:
<?php
上传{
if(文件上传不成功) throw(上传异常);
if(插入数据库不成功) throw(数据库操作异常);
}
//其他代码...try{
上传;
其他;
}catch(上传异常){
必须的补救措施,如删除文件,删除数据库插入记录
}catch(其它异常){
记录log
}
?>

    上面的两种捕获异常的方式,前一种是在异常发生时,立刻捕获;后一种是分散抛异常,集中捕获。那到底应该是哪一种呢?
   如果我们的业务很重要,那么异常越早处理越好,以保证程序在意外情况下能保持业务处理的一致性。比如一个操作有多个前提步骤,突然最后一个步骤异常了,那么其他前提操作都要消除掉才行,保证数据一致性。并且在这种核心业务下,有大量的代码来做善后工作,进行数据补救,这是一种比较悲观的异常
  如果我们的异常不是那么重要,并且在单一入口,MVC风格的应用中,为了保持代码流程的统一,则常常采用后一种异常处理方式,这种异常处理更多强调了业务流程的走向,对善后工作并不是很关心。这是一种乐观的异常
    (3)语言级别的健壮性要求
      在这点上,php是缺失的。以java为例,java是一种面向企业级开发的语言,强调健壮性。java中支持多线程,java认为,多线程被中断这种情况是彻彻底底的无法预料和避免的。所以 java规定,凡是用了多线程,就必须正视这种情况。你要么抛出,不管它,要么捕获,进行处理。总之,你必须面对 InterruptedException这个异常,不准回避。也就是异常发生后应对重要数据业务进行补救,当然你可以不做,但是我会告诉你,这是你应该做的。    这类异常是强制的。更多的异常是非强制的,由程序员决定的。java对异常的这种分类和约束,保证了java程序的健壮性和可信赖度。
    那么异常的意义何在?
    异常就是无法控制的运行时错误,会导致出错时中断正常逻辑运行,该异常代码后面的逻辑都不能继续运行。那么try/catch的好处就是可以把异常造成的逻辑中断破坏降到最小范围内,并且经过补救处理措施后不影响业务逻辑的完整性,乱抛异常和只抛不捕获,或捕获而不补救,会导致数据混乱。 这就是异常处理的一个重要作用,就是在我们精确控制运行时流程的时候,在程序中断的时候,有预见的用try缩小可能出错的影响范围,再及时捕获异常的发生并作出相应的补救,以使逻辑流程仍然能回到正常轨道上来。
       怎样看php的异常?
       我们已经看到了php中的异常机制是很鸡肋的,绝大多数情况下无法自动抛异常,必须用if-else来先进行判断,再手工抛出异常。这种处理方式看起来,比较像是多此一举。手动抛异常的意义就不是很大了,因为你手动抛异常也就意味着你在代码里已经充分预期到错误的出现了,也就算不得真正的“异常”了,而是意料之中的了。还是陷入了纷繁复杂的业务逻辑判断和处理中。java和C++语言做的比较好的就是定义了一堆内置的常见的异常,不需要程序员判断各种异常情况后手工抛出,编译器会代我们进行判断业务是否发生错误,自动抛出异常。作为程序员,则只需要关心异常的捕获和随后补救,而不是像php中关注到底会发生哪些异常啊,用if-else来逐一判断,逐一抛异常。
    php的异常机制很不完美,很多情况下和if-else相比没有明显的优势,这也是php的异常没有普及的原因。当然了,使用了异常也能一定程度上降低耦合性。
    那怎么来完善php原先的异常处理机制呢?这时,就要借助php的错误处理了。PHP提供了一个set_error_handler函数,可以自定义错误处理函数,能够把非致命类型的错误处理都转向到自己定义的函数里进行分析和处理。但是因为出错的地方可能很多,集中处理的话要区分的情况很复杂,所以我们只用这个特性做个跳板。在自定义函数里我们手动抛一个异常出来,杀个回马枪,让try/catch可以捕获并处理这个运行时错误所带来的中断,从而实现扩大try/catch影响范围的目的.

php中的异常机制详解(1)

      php中的异常机制,只能算是一个舶来品,php的书中对异常机制讨论的很少,大多仅停留在语法阶段。有人盛赞php的异常是个好东西,也有人认为php的异常很不给力,也有人一直困惑在php中该不该用异常,怎么用?
    异常本身的语法并不值得讨论,异常的使用场景才是主要的,这里我对比php和java,来看看php里的异常到底是怎么回事,异常到底应该怎么用。
      看到了PPC论坛上的这篇讨论,觉得很有价值,我重新整理了下我的观点,做个总结。
      首先,需要说的是,这里的异常是指php的异常。因为php的异常和其它语言相比有着很大的不同。
      php里的异常,是程序运行中的不符合预期的情况,即一种在程序执行流程里面允许发生,只是和正常流程不同的状况。它是一种不正常的情况,就是按照我们的正常逻辑本不该出错,但仍然会出现的错误,属于逻辑和业务流程的错误,而不是语法上的错误。
    php里的错误则是一种非法的,语法或者环境问题导致的让编译器无法通过检查,甚至无法运行的情况。
    php的异常处理所做的是对你程序运行时出现的某种情况进行处理,并不是错误,异常是程序运行得到的结果不是你想要的。对于程序而言,异常是不可控的,我们无法控制运行时在哪个环节会出错,但是我们可以大致预期到哪些环节会出错,并进行针对性的补救。
    异常(exception)和错误(error)的概念以及区分在各种语言里是不一样的。在java和php里,对错误和异常的界定也是不同的。在php里,它遇到任何的自身错误都会触发一个错误,而不是抛异常(对于一些情况,会同时抛出异常和错误)。php一旦遇到非正常的代码,通常都会触发错误,而不是抛出异常。在这个意义上,如果你想使用异常来处理不可预料的问题,是办不到的。比如说,你想在文件不存在,数据库连接打不开的时候触发异常,是不可行的。这在php里是一种错误,php把它作为错误抛出,而无法作为异常自动捕获。而java则不同,java把很多行为看成是异常并且可捕获。
我们来个最直观最简单的例子吧。就以经典的除零问题为例:
//exception.php
<?php
$a=null;
try{
$a=5/0;
echo $a,PHP_EOL;
}catch(exception $e){
$e->getMessage();
$a=-1;
}
echo $a;
运行结果:
图片1.jpg
下面是java代码:ExceptionTry.java
//ExceptionTry.java
public class ExcepetionTry {
    public static void tp() throws ArithmeticException{
        int a;
        a=5/0;
        System.out.println("运算结果:"+a);
    }
   
    public static void main(String[] args) {
        int a;
        try {           
            a=5/0;
            System.out.println("运算结果:"+a);
        } catch (ArithmeticException e) {
            e.printStackTrace();   
        }finally{
        a = -1;
        System.out.println("运算结果:"+a);
        }
        try {
            ExcepetionTry.tp();
        } catch (Exception e) {
            System.out.println("异常被捕获");
        }
       
    }
}
运行结果:
2011-08-09_205323.png
如果我们把tp方法中的第二条语句改为如下:
a=5/1;

那么结果将是如下:
2011-08-09_205617.png
    由以上运行结果可以看到,对于除0这种“异常”代码,php认为这是一个错误,会直接触发错误(waring也是错误,只是错误等级不一样而已),而不会自动抛异常使进入异常流程,故最终$a的值并不是预想中的-1,也就是说,并没有进入异常分支,也没有处理异常。php只有你主动throw后,才能捕获异常(一般情况是这样的,也有一些异常php可以自动捕获)。
   而对于java,则认为除0属于ArithmeticException,会对其进行捕获,并对异常进行处理。
   也就是说,php实际上是无法自动捕获有意义的异常的,它把所有不正常的情况都视作了错误,你要想捕获这个异常,就得使用if-else结构,保证代码是正常的,然后判断如果除数为0,则手工抛出异常,再捕获。而java则不是这样,java有一套完整的异常机制,内置了很多异常类会自动捕获各种各样的异常。

转:用php说明char和varchar区别

大家在建表时可能经常会遇到类似char和varchar这类的字段类型选择。

如有以下数据结构:

工号 姓名 部门
———————–
1 张三 财务
2 李四 人事
3 王五 销售
……..

我们定义”姓名”为char(10)(静态)的时简单地用php代码表示:
简单地模拟底层数据存储链表$data
$col_num_len  =1;      //工号长度为1
$col_name_len=10;    //姓名长度为10
$col_unit_len   =4;     //部门长度为4
$col_len=$col_num_len+$col_name_len+$col_unit_len+3;         //表示每笔记录的总长度,包括3个分隔符
实现如下:
$data="1|张三      |财务|2|李四      |人事|3|王五      |销售|...";         //简单地模拟底层数据存储链表

阅读剩余部分...

php开发指南之19章:缓存简介(四)

    这一次,我们讲讲前端页面缓存,包括浏览器缓存.
     通常,前端的页面缓存主要有基于HHTP协议和基于浏览器和脚本两种。HTTP协议中有很多报头来描述缓存的。我们可以在HTML页面利用meta tag和PHP程序中通过header来控制.例如:
    <?php
    header('Cache-Control:max-age=86400, must-revalidate');//24小时
    header('Last-Modified:'.gmdate('D, d M Y H:i:s').'GMT');
    header('Expires:'.gmdate('D, d M Y H:i:s', time() + '86400').'GMT');
    echo '我不刷新';再写个HTML文件c.htm:<html>
    <body>
        haha,<a href=cache.php>go</a>
    </body>
</html>
     我们请求127.1/c.htm,点击链接,然后利用浏览器的回退按钮,返回c.htm,再点击链接,如下图左所示,我们发现,当添加了缓存指令后,我们无论如何来回后退和点击链接,下面的网络请求URL这一条始终为灰色,表示浏览器并没有发起实际的网络请求,而是直接调用了存储在用户电脑中的缓存页,除非缓存时间过期,在这期间,即使是实际内容改变了,浏览器也不会去重新读取我们在服务器上的资源。你可以把echo的那一句修改后,再点击,会发现网络请求仍然为灰色。在这种情况下,只有以下三种情况浏览器才会去更新缓存:
(1)缓存到期
(2)缓存被清除;
(3)F5或 ctrl+F5强制刷新。(这一点各种浏览器处理可能存在差异,我的测试环境是firefox 4)  
    当我们屏蔽上面的header指令或者改用如下代码时//告诉客户端浏览器不使用缓存,HTTP 1.1 协议
header("Cache-Control: no-cache, must-revalidate");
//告诉客户端浏览器不使用缓存,兼容HTTP 1.0 协议
header("Pragma: no-cache");
c1.pngc2.png

阅读剩余部分...

php开发指南之19章:缓存简介(三)

        刚刚讲的是最简单的文件缓存,再复杂一点,讲讲稍微复杂点的opcode缓存。
         所谓opcode缓存就是把php在经虚拟机把php代码编译成一种中间码(这种代码就叫opcode)的结果缓存起来(可以缓存到硬盘,也可以到内存),下一次php运行此页面时,只要直接解释这堆代码就行了。这样就省去了flex语法器进行语法编译和大部分语法检查(这个语法检查在多个阶段均存在)的过程,一定程度上提高了php的运行速度,减轻服务器的负荷。eAccelerator就是这么的一款工具,当然它的功效不仅如此。至于eAccelerator的安装和配置我在第一章就讲过了,此处不在赘述。
        Opcode长啥样?我们直观的来看一下。
        首先安装VLD扩展,VLD全名是Vulcan Logic Disassembler,可以用来检测PHP脚本的执行情况。
       【Linux下】:安装VLD:wget http://pecl.php.net/get/vldtar zxvf vld-0.9.1.tgzcd vld-0.9.1phpize./configuremake install编辑php.ini文件激活vld扩展:extension=vld.so如果是在win下,可参考我博客的一篇文章进行编译,http://aiyooyoo.com/index.php/archives/212/。如果你不大会的话,或者觉得麻烦,也可以用我编译好的,在本指南第一章的源代码目录里有。此扩展在php5.3.3-5.3.5测试均可用,其他较早版本应该也可以。同样的,在win下安装扩展的操作不再描述。现在我们写一个文件测试一下,代码如下:
<?php echo "helloword\r";
$data['first']='Hello';
$data['first']['second']='world';echo $data ['first'];
在命令行下执行php -dvld.active=1 g:\bak\temp\tempcode\time.php,得到输出如下
filename:       G:\bak\temp\tempcode\time.phpfunction name:  (null)
number of ops:  13compiled vars:  !0 = $data
line     # *  op                           fetch          ext  return  operands
--------------------------------------------------------------------------------
 2     0  >   EXT_STMT       1      ECHO                                                  'helloword%0D'
 3     2      EXT_STMT      3      ZEND_ASSIGN_DIM                                      !0, 'first'       4      ZEND_OP_DATA                                             'Hello', $1
 4     5      EXT_STMT      6      FETCH_DIM_W                                     $2      !0, 'first'      7      ZEND_ASSIGN_DIM                                        $2, 'second'      8      ZEND_OP_DATA                                             'world', $4
   5    9      EXT_STMT        10      FETCH_DIM_R                                  $5      !0, 'first'       11      ECHO                                                     $5        12    > RETURN                                                   1
branch: #  0; line:     2-    5; sop:     0; eop:    12path #1: 0,welloword   
       从这里我们可以看出,这段代码被分成了13小步执行。看一张C的hello world经过汇编后的代码,有没有发现上面的OPCODE和汇编代码很像。没错,opcode就是php的“汇编代码”。OpCode就是Operation Code,意即操作码的意思。注意:OpCode不是php里的专有名词。 Php里的Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,PHP的语言引擎Zend执行php代码时候,会把php代码经过分成token,词法分析的过程转成opcode,然后顺序执行。
图片2.png
    

阅读剩余部分...

    Page :
  1. 1
  2. 2
  3. 3
  4. 4
  5. ...
  6. 7