变量>> 无法声明变量. 当第一次使用时, 不存在的变量会被创建为 null 值. >> 全局变量在使用前, 需要 global 声明. 这是根据上面得出的自然结果, 因此这是个完美的理由, 但, 如果没有显示的声明, 全局变量甚至无法读取 -- PHP 將悄悄的创建一个局部同名变量取代它. 我还没见过其它语言使用类似的方法处理范围问题. >> 没有引用. PHP所谓的引用是个真正的别名; 这无疑是一种倒退, 不像 Perl 的引用, 也没有像 Python 那样的对象标识传递. >> 没有明显的方式检测和取消引用. >> "引用" 使变量在语言中与众不同. PHP 是动态类型的, 因此变量通常无类型... 除了引用, 它修饰函数定义, 变量语法, 和赋值. 一旦变量被引用(可在任何地方发生), 它就一直是个引用. 没有明显的方法探测和解引用需要的变量值. >> 好吧, 我说谎了. 有些"SPL types" 也作用于变量: $x = new SplBool(true); $x = "foo"; 將失败. 这有点像静态类型, 自己看看. >> A reference can be taken to a key that doesn’t exist within an undefined variable (which becomes an array). Using a non-existent array normally issues a notice, but this does not. >> 通过函数定义的常量称为 taking a string; 这之前, 它们不存在. (这可能实际上是复制 Perl 使用常量的行为.) >> 变量名是大小写敏感的. 函数和类名不是. 使得方法使用驼峰式命名会很奇怪. 结构>> array() 和几个类似的结构不是函数. $func = "array"; $func(); 不工作. >> 数组拆包可以使用 list($a,$b) = .... 操作完成. list() 是类函数语法, 就像数组那样. 我不知道为什么不给一个真正的专用语法, 也不知道为什么名字如些的让人迷惑. >> (int) 很显然的被设计成类似C, 但它不是单独的标记; 在语言中, 没有东西被称为 int. 试试看: var_dump(int)不工作, 它会抛出一个解析错误, 因为参数看起来像是强制转操作符. >> (integer) 是 (int) 的别名. 也有 (bool)/(boolean)和(float)/(double)/(real). >> 有个(array)操作符用来转成数组和 (object) 用来转成对象. 这听起来很贴心, 但常常有个用例: 你可以用 (array) 使得某个函数参数, 既可以是单个元素,也可以是列表, 相同对待. 但这样做不可靠, 因为如果某人传递了单个对象,把它转换成数组將实际上生成了一个包含对象属性的数组. (转换成对象执行了反转操作.) >> include()这类的函数基本上就是C的#include: 他们將其它的文件源码转存到你的文件中. 没有模块系统, 甚至对 PHP 代码也一样. >> 没有类似嵌套或者局部范围的函数或类. 它们都是全局的. include 某文件, 它的变量导入到当前函数范围中(给了文件访问你的变量的能力), 但是函数和类存入全局范围中. >> 追加数组使用 $foo[] = $bar. >> echo 不是函数. >> empty($var) 是如此极端, 对于任何其它东西不表现为函数, 除了变量, e.g. empty($var || $var2), 是个解析错误. 为什么地球上有这种东西, 解析器为什么需要了解 empty ? >> 还有些冗余的语法块: if (...): ... endif;, 等等. 错误处理>> PHP 的一个独特操作符是 @ (实际上从DOS借用过来的), 它隐藏错误. >> PHP 错误不提供栈轨迹. 你不得不安装一个处理器生成它们. (但 fatal errors不行 -- 见下文.) >> PHP 的解析错误通常只抛出解析的状态, 没其它东西了, 使得调试很糟糕. >> PHP 的解析器所指的例如. :: 内部作为 T_PAAMAYIM_NEKUDOTAYIM, 而 << 操作符作为 T_SL. 我说 "内部的", 但像上面说的, 给程序员显示的 :: 或 << 出现在了错误的位置. >> 大多数错误处理打印给服务器日志打印一行错误日志, 没人看到而一直进行. >> E_STRICT看起来像那么回事, 但它实际上没多少保护, 没有文档显示它实际上是做什么的. >> E_ALL包含了所有的错误类别 -- 除了 E_STRICT. >> 关于什么允许而什么不允许是古怪而不一致的. 我不知道 E_STRICT 是怎样适用于这里的, 但这些却是正确的: >> 试图访问不存在的对象属性, 如, $foo->x. (warning) >> 使用变量做为函数名, 或者变量名, 或者类名. (silent) >> 试图使用未定义常量. (notice) >> 试图访问非对象类型的属性.(notice) >> 试图使用不存在的变量名.(notice) >> 2 < "foo" (隐藏) >> foreach (2 as $foo); (warning) 而下面这些不行: >> 试图访问不存在的类常量, 如 $foo::x. (fatal error) >> 使用字符串常量作为函数名, 或变量名, 或类名. (parse error) >> 试图调用一个示定义函数. (fatal error) >> Leaving off a semicolon on the last statement in a block or file. (parse error) >> 使用 list 和其它准内建宏作为方法名. (parse error) >> 用下标访问函数的返回值, 如: foo()[0]. (parse error; 已在 5.4 中修复) 在列表的其他地方也有几个关于其它怪异解析错误的好例子 >> __toString 方法不能抛出异常. 如果你尝试, PHP 將 ... 呃, 抛出一个异常. (实际上是个 fatal error, 可以被通过的, 除了...) >> PHP 错误和 PHP 异常是完全不同的物种. 它们不能相互作用. >> PHP 错误 (内部, 称为 trigger_error)不能被 try/catch 捕获. >> 同样, 异常不能通过 set_error_handler 安装的错误处理器触发错误. >> 作为替代, 有一个单独的 set_exception_handler 可以处理未捕获的异常, 因为用 try 块包装你程序入口在 mod_pho 模块中是不可能的. >> Fatal 错误 (例如, new ClassDoesntExist()) 不能被任何东西捕获. 大量的完全无害的操作会抛出 fatal 错误, 由 于一些有争议的原因被迫终结你的程序. 关闭函数仍然运行, 但它们无法获取栈轨迹(它们运行在上层), 它们很难告知该程序是由一个错误还是程序的正常运行结束. >> 没有 finally 结构, 使得包装代码 (注册处理器, 运行代码, 注销处理器; monkeypatch, 运行测试, unmonkeypatch) 很难看, 很难写. 尽管 OO 和异常大量的复制了Java的模式, 这是故意的, 因为 finally "在PHP上下文中, 只得其形不得其神".Huh ? |