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个回答

328

文档文档 是我推荐的选择。我还没有遇到过比这更全面的编程语言在线文档 - 其他所有内容都需要从各个网站和手册中拼凑而成。


60
我同意。通常能够在浏览器中输入www.php.net/function_name,然后获得相应参考资料是非常好的。 - Allain Lalonde
1
这是PHP的一个很棒的功能,但我并不认为它是隐藏的……如果你曾经在Google上搜索过方法参数等内容,你会发现php.net。 - John B
27
我也同意。这份手册最好的地方就是用户评论,我很少看到其他文档有这样的功能。这些评论可能包含宝贵的信息。唯一的缺点是,在我看来,它们被修剪得有点太快了。 - Sander Marechal
3
“little bit less read-able” 是“有点不易读懂”的意思。我从未理解过 MSDN,而 PHP 文档则简单明了易懂。 - lauriys
3
不同意。文档之所以“好”,仅仅是因为一些用户评论填补了官方说明中的漏洞。 - Rob Howard
显示剩余9条评论

179

数组。从回答这个问题的人们来看,我不认为人们完全理解PHP中的数组有多么简单和有用。PHP数组同时充当列表、映射、堆栈和通用数据结构。数组在语言核心中实现,并且在许多地方使用,这导致了良好的CPU缓存局部性。Perl和Python都使用单独的语言结构来表示列表和映射,这导致了更多的复制和潜在的混淆转换。


11
PHP 数组元素是有序的。 - user8134
117
我从 PHP 初次转向 C# 几乎让我崩溃。在 C# 中,数组只是具有静态大小和数字索引的简单结构。而在 PHP 中,数组则是宇宙中的胶带! - Dinah
4
我也同意。在完成一项大学Java作业时,我惊讶地发现Java非常死板,完全没有灵活性。这让我更加欣赏PHP数组的优点。 - Christian
11
我相信PHP数组是很好的,但是对于那个诋毁C#数组的评论投了40票?如果C#数组不适合需求,还有很多其他选择。ArrayList和泛型集合都非常强大。还有许多特定需求的不同类型的集合可供选择。在这方面,PHP唯一的优点就是它没有提供程序员必须决定使用哪个选项。你要么使用数组,要么就没有可索引的变量。 - G-Wiz
24
另一方面,数组的语法非常糟糕。在许多脚本语言中,您可以像这样创建一个简单的二维数组:[[1, 2], [3, 4]],与PHP版本进行比较:array(array(1, 2), array(3, 4)) - Rene Saarsoo
显示剩余10条评论

167

流处理程序允许您使用在大多数其他语言中难以实现的逻辑扩展“文件系统”。

例如,使用MS-Excel Stream handler,您可以按照以下方式创建 MS Excel 文件:

$fp = fopen("xlsfile://tmp/test.xls", "wb");
if (!is_resource($fp)) { 
    die("Cannot open excel file");
}

$data= array(
    array("Name" => "Bob Loblaw", "Age" => 50),  
    array("Name" => "Popo Jijo", "Age" => 75),  
    array("Name" => "Tiny Tim", "Age" => 90)
); 

fwrite($fp, serialize($data));
fclose($fp);

我相信KIO框架也可以实现这个功能,但这仅适用于基于KDE的桌面应用程序。 - MiffTheFox
21
在我看来,采用正确的面向对象方法比使用流处理程序好得多。虽然能够读写Excel文件很不错,但一定要这样操作吗? - Anti Veeranna
3
也许是这样,但这种方法将复杂性封装在一个常见的接口中,适用于大多数PHP开发人员...而无需要求他们学习可能超出其能力范围的面向对象概念。 - Allain Lalonde
13
如果您正在使用Amazon S3,请查看Zend_Amazon_S3,它为像's3://{bucket-name}/path'这样的URL提供了流接口。 - davidtbernal
@Allain Lalonde:我认为任何不能理解面向对象编程概念的人都不应该编写这种复杂代码。此外,这个方法如何与其他流处理程序结合?如果我想通过ftp://上传那个XLS文件怎么办? - Matti Virkkunen
显示剩余3条评论

131
魔术方法是一种通用方法,当你调用一个不存在的方法、给不存在的属性赋值或读取不存在的属性等情况时会被调用。
interface AllMagicMethods {
    // accessing undefined or invisible (e.g. private) properties
    public function __get($fieldName);
    public function __set($fieldName, $value);
    public function __isset($fieldName);
    public function __unset($fieldName);

    // calling undefined or invisible (e.g. private) methods
    public function __call($funcName, $args);
    public static function __callStatic($funcName, $args); // as of PHP 5.3

    // on serialize() / unserialize()
    public function __sleep();
    public function __wakeup();

    // conversion to string (e.g. with (string) $obj, echo $obj, strlen($obj), ...)
    public function __toString();

    // calling the object like a function (e.g. $obj($arg, $arg2))
    public function __invoke($arguments, $...);

    // called on var_export()
    public static function __set_state($array);
}

在这里,一个C++开发人员可能会注意到,PHP允许重载一些运算符,例如()(string)。实际上,PHP甚至允许更多的重载,例如[]运算符(ArrayAccess)、foreach语言结构(IteratorIteratorAggregate)以及count函数(Countable)。


4
有关魔术方法的有用示例,请访问http://phpcodetips.blogspot.com/2008/07/domain-model-validation.html。 - grom
6
不同意。相比Smalltalk、Ruby和Python中类似的功能,这个更弱(很可能是从其中一个语言中复制来的)。 - finnw
34
尽管 PHP 在这方面的实现不如其他语言,但这并不影响在 PHP 中使用它仍然很有用。 - Allain Lalonde
2
__call()在具有映射域名的框架中非常好用,例如domain.com/controller/method/。 - alex
7
魔术方法速度非常慢,要谨慎使用。请小心操作。 - Alex Weinstein
显示剩余7条评论

95
标准类是一个整洁的容器。我最近才了解到它。

与其使用数组来保存多个属性,

$person = array();
$person['name'] = 'bob';
$person['age'] = 5;
您可以使用标准类。
$person = new stdClass();
$person->name = 'bob';
$person->age = 5;

当在字符串中访问这些变量时,这将特别有帮助。

$string = $person['name'] . ' is ' . $person['age'] . ' years old.';
// vs
$string = "$person->name is $person->age years old.";

43
“{$person['name']} is {$person['age']} years old” 表达正确。 - Kornel
27
person[name]今年$person[age]岁。 - majelbstoat
16
$string = sprintf("%s今年%d岁。", $person['name'], $person['age']); - Daniel Sloof
60
在这个话题上,(目标)数组(“name” => 'bob','age' => 5)… - Annika Backstrom
30
去掉引号会拖慢脚本的速度,因为PHP解释器将查看是否使用define(...)设置了“name”和“age”。考虑到在每种情况下都可能完全翻转访问的键,这也是一种不好的做法:define('age','name'); define('name','age'); - brianreavis
显示剩余11条评论

90

包含文件可以有一个返回值,您可以将其分配给一个变量。

// config.php
return array(
    'db' => array(
        'host' => 'example.org',
        'user' => 'usr',
        // ...
    ),
    // ...
);

// index.php
$config = include 'config.php';
echo $config['db']['host']; // example.org

@Peter 非常有用,用于处理db->localhost异常错误。 - Talvi Watia
设置一个快速且简单的配置文件非常方便。 - Frank Farmer
为什么要返回这个数组?如果一个包含文件包含一个数组,它可以立即在包含中使用。 - fabrik
5
@fabrik的原因是它将成为全局变量并在整个主作用域中可用。这相当让人不舒服,这种写法要好得多。 - Mikulas Dite
我曾在Yii框架上工作过一个项目,该项目有一个配置文件,其中返回了如下的数组。现在我明白为什么文件是这样的了。 - Simer Twilio Toronto developer

83

你可以利用 or 运算符的优先级低于 = 运算符的这一事实来实现:

$page = (int) @$_GET['page'] 
  or $page = 1;
如果第一个赋值的值评估为true,则忽略第二个赋值。另一个例子:
$record = get_record($id) 
  or throw new Exception("...");

7
我对此并不完全认同,尽管它似乎没有错误的倾向,但它本身就很不符合直觉,这可能会促成错误。 - thomasrutter
14
@Pies 提供了一种方式,但代码比较混乱:$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; 这种方式的好处是不需要使用错误抑制。 - DisgruntledGoat
3
重新考虑后,由于您正在寻找一个整数,因此您可以使用以下代码替代:$page = is_int($_GET['page']) ? $_GET['page'] : 1;。 - DisgruntledGoat
4
值得注意的是,如果or之前的代码结果为数字值0,则or之后的代码将会执行。因此,从语义上讲,使用类似于$_GET['page']的代码可能不太可能发生这种情况,但是显然这种情况可能会出现,所以需要注意。 - eyelidlessness
3
值得注意的是,or 运算符是 || 运算符的低优先级版本。此外,加一赞,因为它非常表达力,而且我经常忘记它是可能的。它应该更经常地被使用,而且它所做的事情绝对清晰明了。但我不知道“真正的男人”是如何编码的,所以我无法评论这个。 - eyelidlessness
显示剩余12条评论

80

__autoload()函数可以通过set_include_path()来协助(class-)文件的自动包含。

在PHP5中,当进行OOP编程时,无需指定长列表的“include_once”语句。

只需定义一小组目录,其中类库文件被合理地构造,并设置自动包含路径即可:

set_include_path(get_include_path() . PATH_SEPARATOR . '../libs/');`
现在是__autoload()例程:
function __autoload($classname) {
    // every class is stored in a file "libs/classname.class.php"

    // note: temporary alter error_reporting to prevent WARNINGS
    // Do not suppress errors with a @ - syntax errors will fail silently!

    include_once($classname . '.class.php');
}

现在,PHP将自动按需包含所需的文件,节省解析时间和内存。


spl_autoload_register() 使用更佳吗? - alex
19
当然可以!__autoload() 是 PHP4 的方法,而 spl_autoload_register() 则是一种非破坏性的“链式调用”自动加载方法。 - Willem
3
一个方便的功能,但唯一需要注意的是当你找到一个特定类的实例时,它会使查找类文件的位置变得有点困难。在顶部明确定义包含的内容可以给你一个有限的涉及类和它们确切位置的列表。 - Cory House
这是一个不错的功能,但只是为了解决没有预编译代码的情况,因此它不知道类将在哪里。这样做的一个很大的缺点是,即使它们位于不同的命名空间中,您也不能拥有两个具有相同名称的类。 - Kibbee
3
请查看PHP标准工作组的PSR-0提案(包括ZF、Symfony、Doctrine、CakePHP、Solar等开发者),在实现自动加载时参考此提案:http://groups.google.com/group/php-standards/web/psr-0-final-proposal。 - Philippe Gerber
显示剩余2条评论

76

变量变量和函数毫无疑问!

$foo = 'bar';
$bar = 'foobar';
echo $$foo;    //This outputs foobar

function bar() {
    echo 'Hello world!';
}

function foobar() {
    echo 'What a wonderful world!';
}
$foo();    //This outputs Hello world!
$$foo();    //This outputs What a wonderful world!

相同的概念适用于对象参数($ some_object-> $ some_variable);

非常好。使用循环和模式编码变得非常容易,比 eval 更快更可控(感谢 @Ross 和 @Joshi Spawnbrood!)。


111
变量变量实际上使代码更难读懂,容易出错。 - Elzo Valugi
8
人们真的会用这个吗?天啊,我讨厌读这些消息来源。 - Gary Willoughby
27
可变变量是 PHP 提供的最糟糕的功能之一。 - davidtbernal
10
有9次中,有10次变量最好用数组代替,这样您可以将所有数据放在一个地方,可以遍历等等。只有在一些非常特定的情况下才可能有用。 - Jasper Bekkers
7
请不要让新手使用那个“功能”。 - whiskeysierra
显示剩余14条评论

76

易用性。最大的特点是新开发者可以轻松地编写“可工作的”脚本并理解代码。

最糟糕的特点是新开发者可以轻松地编写“可工作的”脚本并认为他们理解了代码。

PHP社区的开放性以及大量可作为开源项目使用的PHP项目,对于进入开发世界的人来说不太具有威慑力,就像你一样,它可以成为进入更成熟语言的垫脚石。

我不想讨论技术问题,因为很多人之前已经讨论过了,但如果你将PHP看作一个社区而不是一个网络语言,一个明显欢迎你开始开发的社区,那么它的好处真的不言而喻。


3
绝对是一条好评论。Python是我学的第一门语言,非常棒,但我感到理解能力有限的项目不多,这创造了一定的障碍。使用PHP,我可以在文档中查找几乎任何内容并解决问题……网络上可用的资源令人惊叹。 - dscher

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