PHP的隐藏功能是什么?

174

我知道这个问题听起来像是在刻意追求积分,但是让我解释一下我的意图。

我大学毕业后在一个PHP团队找到了工作。我在那里工作了一年半,认为自己已经学会了所有关于编程的东西。

后来,我在一个规模相当大的公司担任一人内部开发岗位,所有的工作都是用C#完成的。为了胜任这份工作,我开始阅读大量的博客和书籍,很快就意识到我曾经认为自己已经掌握了所有技能是多么的错误。我学习了单元测试、依赖注入、装饰器模式、松耦合设计原则、组合优于继承的争论等等——至今仍在不断吸收学习。毫无疑问,过去一年中我的编程风格完全改变了。

现在,我发现自己正在为朋友的初创公司开发一个PHP项目,并感到完全受限制,与使用C#编程形成了鲜明对比。对我来说,所有类范围内的变量必须通过'$this->'来引用真的很烦人。我很烦恼试过的所有IDE都没有很好的智能提示,而我的SimpleTest单元测试方法必须以单词“test”开头。动态类型让我不能隐式地指定方法期望的参数类型,并且您必须编写switch语句来进行方法重载。我无法忍受你不能有嵌套的命名空间并且必须使用::运算符来调用基类的构造函数。

现在,我并不想发起PHP vs C#的辩论,我只是想说,我相信在PHP中有一些功能我还不知道或者还没有正确使用过。我已经习惯了C#的编程环境,很难看到外面的新鲜事物。

因此,我想问问您,您最喜欢的PHP功能是什么?在PHP中有哪些事情是您可以做但.NET语言更难实现的呢?


面向对象编程的缺陷?对我来说,这是你发现的最糟糕的“隐藏”功能。 - knoopx
这些线程有点有趣...因为对于我所在的团队,“隐藏功能”是一个代表“漏洞”的代码短语。你知道吗...有时候发现一个隐藏的功能并不一定是好事... - Ganesh Shankar
@Ganesh 一个人的错误可能是另一个人的隐藏功能... - Xeoncross
78个回答

16

使用ob_start()进行输出缓冲比大多数人想象的要更有用。 这里的第一个隐藏功能是ob_start可以接受回调函数:

function twiterize($text) {
    // Replace @somename with the full twitter handle
    return preg_replace("(\s+)@(\w)+(\s+)", "http://www.twitter.com/${2}", $text);
}

ob_start(twiterize);

其次,您可以嵌套输出缓冲区... 使用上一个示例:

ob_start(parseTemplate);
 // ... 
 ob_start(twiterize);
   // ...
 ob_end_flush();
 // ... 
ob_end_flush();

通过使用这两个工具的不同组合,帮助内容、文本广告、字典/索引功能、链接化、用于跟踪目的的链接重定向、模板引擎等所有这些东西都非常容易。


2
我知道这很懒,但我使用输出缓冲,因此在我的代码中深入添加标题并完全避免已发送错误的标题。这在模板中最为明显,如果在嵌套模板的某个深处发生错误,则可以简单地添加一个标题以将用户重定向到错误页面。 - DeveloperChris
就DeveloperChris的帖子进行扩展,我发现大多数人都没有意识到这是一种非常好的方法,可以在不必担心字符从何而来的情况下轻松转换字符。我大多数打字都用波兰页面,并且它们需要使用ISO-8859-2。然而,大多数简单的编辑器只能做Windows-1250。我曾经看过源文件,其中包含直接编码为8859-2的翻译表,但是这很难维护。在它的顶部放置一个漂亮的转换缓冲区,就可以解决很大的问题,代码也突然变得更易读。 - Egon_Freeman

16

你可以使用 break N; 来退出嵌套循环(以弥补没有 goto 的缺陷)。例如:

for (int i=0; i<100; i++) {
    foreach ($myarr as $item) {
        if ($item['name'] == 'abort')
            break 2;
    }
}

更多信息请点击这里 - http://php.net/manual/en/control-structures.break.php


我猜这个“特性”最好还是保持隐藏,否则我们很快就会有许多使用GOTO的PHP“程序员”。GOTO是邪恶的!但无论如何,我不知道那个...不错 :) - user312650
2
实际上,goto 已经不再缺少了… - NikiC
只要我们不处理需要“释放”(deallocated)的对象/结构,它就非常有用且安全。总的来说,我确实在其他语言中很想念这个 - 我认为它比任何GOTO更清晰和明确。 - Egon_Freeman

15

实际上,您并不完全正确。您可以指定方法所需的类型,它会按照您期望的方式工作。

function foo ( array $param0, stdClass $param1 );

注意:此仅适用于“数组”和对象名称。

以此类推,您甚至可以将自己的类作为期望参数传递。如果使用其他方法/函数进行调用,将导致致命错误。

关于PHP智能感知(intellisense)的另一个提示。我们使用ZendStudio,如果您为方法编写良好的PHP文档,则其将在提示时查看这些文档,从而可以更好地工作。


2
根据http://ch2.php.net/language.oop5.typehinting,"string"不支持类型提示。从PHP 5.1开始支持"array",自5.0以来支持特定的对象类型。 - JW.
1
为了加强JW,当进行类型提示时不支持标量类型(除了数组),但是在进行类型转换时支持所有类型。 - dcousineau
3
直到你说ZendStudio是一个可以使用的IDE,我才和你意见一致。 - Jeremy Logan
从PHP 5.4开始,标量类型提示将可用。 - NikiC
1
此外,注释中写道:“这仅适用于'array'和对象名称。”但是如果要完全追求严谨,它应该写成:“这仅适用于'array'和类名。” - Wil Moore III

13

除了能立即访问并开始编写网站所需的任何内容外,还有什么其他的东西呢?

除了魔术方法和反射之外,一些有趣的函数包括:

  1. serialize / unserialize - 通过sql、cookies、进程、平面文件保存状态。非常棒。
  2. json_encode / json_decode - 瞬间实现AJAX乐趣
  3. get_class - 在疲惫的松散类型时非常有用
  4. call_user_func_array - 当您可以将代码作为字符串处理时非常强大(考虑动态)
  5. method_exists - 反射
  6. func_num_args / func_get_arg - 未知参数ftw
  7. set_error_handler / set_exception_handler - 对于脚本语言来说具有非常好的调试能力

作为其副作用,您会拥有一个严重污染的全局命名空间。 - cdmckay

13

日期函数。我整天都要处理很多时间信息和日期字符串,所以像 strftime()strtotime() 这样的函数真是太棒了。


6
请确保查看 DateTime。http://php.net/datetime - Annika Backstrom
2
实际上strtotime很糟糕,因为其中的魔法没有任何文档说明,并且您无法使用自定义格式进行解析。-1 - whiskeysierra
1
同意上面的评论;strtotime()很糟糕,但是5.3的DateTime更好(因为您可以精确指定输入格式)。 - El Yobo
3
我完全不同意。在DateTime出现之前,用PHP处理日期是非常糟糕的。 - cdmckay

13

a) 手册 - 非常全面、最新,并且是解决问题时的灵感巨大来源——卡住了?浏览/搜索手册,问题很快就能解决。

b) 数组 - 它们是可塑性的,关联索引的,可以轻松嵌套(!)以构成一些奇怪的数据结构,而且有许多函数仅用于数组操作。哦,我提到过像将单独的变量视为值数组吗?

c) eval() 和类似的结构(如动态变量和函数名称),它们允许更大的灵活性(只要你知道自己在做什么,还是相对安全的)。没有什么比程序基本上可以自己定义其流程(甚至具体执行)更好了。

d) 最容易被忽视的事情:由于 ZEND 引擎中几乎所有东西都是 zVal(本质上是指针引用的集合),因此能够将几乎任何东西作为函数返回值返回。


另外,我想指出一个很棒的功能,但与语言本身相关性不大(因此单独列出):

e) 编写C扩展的便利性(主要是其他对象的接口,如 OpenAL 或 SDL)——很好的源代码结构,内部和外部一样多的强大工具——如果您需要进一步扩展功能,这非常有用。


4
我已经全职使用 PHP 写了 5 年了,但从未遇到过任何需要合法使用 eval() 或变量变量的情况。 - Frank Farmer
1
使用eval()函数编写的程序可读性不佳。在我看来比“goto”还糟糕,但就像“goto”一样,可能有合法的用途。 - Ivan Vučica
@Frank:当与某人一起进行极端GET操作(接近URI长度限制)的编码时非常有用。声明一个表格并通过自动输入清理来驱动它。虽然不是非常必要,但它使我的生活变得更加轻松。@Ivan:我同意,这很可怕。另一方面,有些情况下,类似但又不同的函数需要围绕一个共同的核心。有一段时间,对我来说最容易的方法就是在运行时生成它们,因为被接受的标准是将PHP函数声明为界面使用的外部命令。节省了大量时间。 - Egon_Freeman

13

Ctype函数在基本字符验证方面比preg_match()更快。

ctype_alnum() — 检查是否为字母数字字符
ctype_alpha() — 检查是否为字母字符
ctype_cntrl() — 检查是否为控制字符
ctype_digit() — 检查是否为数字字符
...等等...


非常好 - 我从未听说过这些,它们默认启用,无需安装或配置其他PHP模块。有人能说明为什么它们不经常使用吗? - cam8001

12

通过错误控制运算符 @ 来抑制错误,几乎永远不应该使用。它会促使编程者变得懒惰和没有防御性,因为它只是忽略了错误,并且会在所有类型(甚至致命错误)的错误被抑制后,造成调试方面的噩梦。在某些情况下,这可能会导致性能下降(特别是在抑制大量错误时)。


2
我很高兴你说“几乎从不”。函数fopen()因无法打开文件而引发警告*并返回可测试的失败值而臭名昭著。唯一的解决方案是,不幸的是,使用@fopen()。 - staticsan
1
是的,没错。关于它的“隐藏”部分是你通常不应该使用它 ;) - Justin Johnson
2
好的防御性编程不仅仅是忽略问题。此外,在使用 issetempty 时,您不应该收到任何通知。 - Justin Johnson
2
Shadow: 如果你收到了很多通知,那就意味着你的编码实践不够好。压制错误是一种掩耳盗铃的态度。它可能会回来咬你一口。如果一个值应该存在但实际上不存在,那么这就是一个错误。如果这个值可以未定义,那么你应该进行测试。否则可能会导致安全漏洞。 - DeveloperChris
1
@staticsan:确实如此,但这不仅仅是fopen()。大多数处理外部数据源的函数,尤其是在网络上,都存在这个缺陷。连接到首选环境之外总是有风险的,99%的时间有一种方法可以测试失败。然后还有那些既不抛出错误也不返回可测试的失败结果的函数,但我手头上想不起来一个(尽管我记得至少看到过一个),所以并非全都糟糕。不过,拥有更多警告总比没有好,并且像GOTO一样使用@ - 应该给予尊重。 - Egon_Freeman
显示剩余8条评论

12

filter_var 函数。不是什么秘密,但相对比较新。


10

最近我把我的第一个GUI应用程序以PHP编写完成并交付给了付费客户!它可以从条形码阅读器或GUI推按钮、复选框、单选按钮或文本字段中收集数据,将其存储到SQLite或远程MySQL数据库中,启动其他Windows应用程序,发送压缩的XML报告作为电子邮件附件,加密和解密存储的数据,甚至在完成时播放声音。

我使用miniPHPWinbinder完成了这个应用程序。这是不是很神秘?我猜没有多少PHP开发者真正尝试过这样做。


我猜很少有PHP开发人员尝试过它,因为在PHP连接到操作系统API方面的支持较少。 - eyelidlessness
2
-1,不试一试是有原因的。 - whiskeysierra
1
我使用Winbinder、PHP-GTK和许多其他工具。至于与操作系统的连接,这就是为什么一些巧妙的库存在,比如php-opengl或php-openal。我知道大多数应该用C++编写,但这仍然是一个有趣的挑战。最重要的是,它消除了“正确的Windows应用程序”中发现的大部分混乱 - 我不需要繁重的功能和多年演变而来的各种聪明才智,现在已经成为“标准” - 它只会使我的代码混乱到我无法再认识它的程度。创建时3k vs 300字节源码,有人吗? - Egon_Freeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接