标签 编程语言 下的文章

世界上编程方面的最大的出版商 Packt Publishing 最近对 11000 名访客进行了调查,根据调查结果,Python 和 JavaScript 是当今最流行的编程语言,而 Java 紧随其后,排名第三。

调查内容包括开发者使用的编程语言、喜欢的框架、薪酬信息等。调查显示,如果就编程人员每天都要使用的语言来看,当今前10名的编程语言排名是 Python、JavaScript、Java、PHP、HTML(虽然不算编程语言)、 C#、SQL、CSS(也不算) 、C++ 和 R。

从之前的类似调查中可以发现,所有的调查均显示 Python 和 JavaScript 得到了极大流行。

Packt Publishing 的调查发现,编程人员薪水和以上排名完全不同,诸如 bash、Perl 和 Scala 语言编程人员获得的年薪平均超过了 8 万美元,甚至 Bash 编程语言人员的薪酬达到了 10 万美元,而 PHP 和 C 语言编程人员年薪几乎没有到达 4 万美元。

而在 Web 开发人员使用的工具方面,AngularJS 取得了第一,其次是 Facebook 的 React.js 框架、Node.js、Docker、Laravel、 Bootstrap、WordPress 和 AWS。

过去几年最流行的新编程语言排行榜当中,毫无疑问 Swift 高居榜首,其次是 C#、Go、Rust 和 Elixir。

新的框架方面, Docker 也如预期的那样得到第一,Apache Spark 和 AWS 分列二、三名。

更多的调查结果,可以看看 Packt Publishing 的报告(需注册)。

是的,你知道的,苹果编程语言 Swift 已经开源了。其实我们并不应该感到意外,因为在六个月以前苹果就已经宣布了这个消息

苹果宣布推出开源 Swift 社区。一个专用于开源 Swift 社区的新网站已经就位,网站首页显示以下信息:

我们对 Swift 开源感到兴奋。在苹果推出了编程语言 Swift 之后,它很快成为历史上增长最快的语言之一。Swift 可以编写出难以置信的又快又安全的软件。目前,Swift 是开源的,你可以将这个最好的通用编程语言用在各种地方。

swift.org 这个网站将会作为一站式网站,它会提供各种资料的下载,包括各种平台,社区指南,最新消息,入门教程,为开源 Swift 做贡献的说明,文件和一些其他的指南。 如果你正期待着学习 Swift,那么必须收藏这个网站。

在苹果的这次宣布中,一个用于方便分享和构建代码的包管理器已经可用了。

对于所有的 Linux 使用者来说,最重要的是,源代码已经可以从 Github获得了.你可以从以下链接 Checkout 它:

除此之外,对于 ubuntu 14.04 和 15.10 版本还有预编译的二进制文件。

不要急着在产品环境中使用它们,因为这些都是开发分支而不适合于产品环境。因此现在应避免使用在产品环境中,一旦发布了 Linux 下 Swift 的稳定版本,我希望 ubuntu 会把它包含在 umake中,和 Visual Studio Code 放一起。


via: http://itsfoss.com/swift-open-source-linux/

作者:Abhishek 译者:Flowsnow 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

编程语言不仅仅是开发者用来创建程序或表达算法的工具,它们也是对创造力进行编码和解码的仪器。通过观察编程语言的历史,我们在追求为解决问题找到一个更好的方法,促进协作,构建好的产品以及重用他人的工作上得到一个独特的观点。

我们有大约 70% 的客户向我们的服务发送应用日志,因此我们能追踪哪种语言是最流行的,以及哪种语言获得了开发人员的关注。

基于从2012年以来的历史的GitHub 归档GitHut数据,我们分析了GitHub上大部分开发者的动作并绘制成你下面看到的信息图表。我们主要关注:

  • 活跃库的数量,这是反应了人们正在研究的项目的有用度量。
  • 每种语言总的推送数量以及每个库的平均推送次数。这些指标是由某种语言编写的项目的创新效率的指示器。
  • 每个库新的fork数和发现的问题数目,这也显示了活跃度和创新性。
  • 每个库新的观察者,这是开发人员兴趣的指示器。

查看信息图表并告诉我们你的想法!在你的同龄人中是怎么选择你使用的语言的?


via: https://www.loggly.com/blog/the-most-popular-programming-languages-in-to-github-since-2012/

作者:Justin Mares 译者:ictlyh 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

我们钟爱我们已知的。

当今许多知名的编程语言已经都非常古老了。PHP 语言20年、Python 语言23年、HTML 语言21年、Ruby 语言和 JavaScript 语言已经19年,C 语言更是高达42年之久。

这是没人能预料得到的,即使是计算机科学家 Brian Kernighan 也一样。他是写著第一本关于 C 语言的作者之一,直到今天这本书还在印刷着。(C 语言本身的发明者 Dennis Ritchie 是 Kernighan 的合著者,他于 2011 年已辞世。)

“我依稀记得早期跟编辑们的谈话,告诉他们我们已经卖出了5000册左右的量,”最近采访 Kernighan 时他告诉我说。“我们设法做的更好。我没有想到的是在2014年的教科书里学生仍然在使用第一个版本的书。”

关于 C 语言的持久性特别显著的就是 Google 开发出了新的语言 Go,解决同一问题比用 C 语言更有效率。不过,我仍然很难想象 Go 能彻底杀死 C,无论它有多么好。

“大多数语言并不会消失或者至少很大一部分用户承认它们不会消失,”他说。“C 语言仍然在一定的领域独领风骚,所以它很接地气。”

编写所熟悉的

为什么某些计算机编程语言要比其它的更流行?因为开发者都选择使用它们。逻辑上来说,这解释已经足够,但还想深入了解为什么开发人员会选择使用它们呢,这就有点棘手了。

分别来自普林斯顿大学和加州大学伯克利分校的研究者 Ari Rabkin 和 Leo Meyerovich 花费了两年时间来研究解决上面的问题。他们的研究报告,《编程语言使用情况实例分析》,记录了对超过 200,000 个 Sourceforge 项目和超过 13,000 个程序员投票结果的分析。

他们主要的发现是什么呢?大多数时候程序员选择的编程语言都是他们所熟悉的。

“这些我们使用的语言还继续存在是因为我们经常使用他们,” Rabkin 告诉我。“例如:天文学家就经常使用 IDL [交互式数据语言]来开发他们的计算机程序,并不是因为它具有什么特殊的亮点功能或其它特点,而是因为用它形成习惯了。他们已经用些语言构建出很优秀的程序了,并且想保持原状。”

换句话说,它部分要归功于这些语言所创立的知名度仍保持较高。当然,这并不意味着流行的语言不会变化。Rabkin 指出我们今天在使用的 C 语言就跟 Kernighan 第一次创建时的一点都不同,那时的 C 编译器跟现代的也不是完全兼容。

“有一个古老的,关于工程师的笑话。工程师被问到哪一种编程语言人们会使用30年,他说,‘我不知道,但它总会被叫做 Fortran’,” Rabkin 说到。“长期存活的语言跟他们在70年代和80年代刚设计出来的时候不太一样了。人们通常都是在上面增加功能,而不会删除功能,因为要保持向后兼容,但有些功能会被修正。”

向后兼容意思就是当语言升级后,程序员不仅可以使用升级语言的新特性,也不用回去重写已经实现的老代码块。老的“遗留代码”的语法规则已经不用了,但舍弃是要花成本的。只要它们存在,我们就有理由相信相关的语言也会存在。

PHP: 存活长久语言的一个案例学习

遗留代码指的是用过时的源代码编写的程序或部分程序。想想看,一个企业或工程项目的关键程序功能部分是用没人维护的编程语言写出来的。因为它们仍起着作用,用现代的源代码重写非常困难或着代价太高,所以它们不得不保留下来,即使其它部分的代码都变动了,程序员也必须不断折腾以保证它们能正常工作。

任何编程语言,存在了超过几十年时间都具有某种形式的遗留代码问题, PHP 也不例外。PHP 是一个很有趣的例子,因为它的遗留代码跟现在的代码明显不同,支持者或评论家都承认这是一个巨大的进步。

Andi Gutmans 是已经成为 PHP4 的标准编译器的 Zend Engine 的发明者之一。Gutmans 说他和搭档本来是想改进完善 PHP3 的,他们的工作如此成功,以至于 PHP 的原发明者 Rasmus Lerdorf 也加入他们的项目。结果就成为了 PHP4 和他的后续者 PHP5 的编译器。

因此,当今的 PHP 与它的祖先——即最开始的 PHP 是完全不同的。然而,在 Gutmans 看来,在用古老的 PHP 语言版本写的遗留代码的地方一直存在着偏见以至于上升到整个语言的高度。比如 PHP 充满着安全漏洞或没有“集群”功能来支持大规模的计算任务等概念。

“批评 PHP 的人们通常批评的是在 1998 年时候的 PHP 版本,”他说。“这些人都没有与时俱进。当今的 PHP 已经有了很成熟的生态系统了。”

如今,Gutmans 说,他作为一个管理者最重要的事情就是鼓励人们升级到最新版本。“PHP有个很大的社区,足以支持您的遗留代码的问题,”他说。“但总的来说,我们的社区大部分都在 PHP5.3 及以上的。”

问题是,任何语言用户都不会全部升级到最新版本。这就是为什么 Python 用户仍在使用 2000 年发布的 Python 2,而不是使用 2008 年发布的 Python 3 的原因。甚至在六年后,大多数像 Google 这样的用户仍没有升级。这种情况是多种原因造成的,但它使得很多开发者在承担风险。

“任何东西都不会消亡的,”Rabkin 说。“任何语言的遗留代码都会一直存在。重写的代价是非常高昂的,如果它们不出问题就不要去改动。”

开发者是稀缺的资源

当然,开发者是不会选择那些仅仅只是为了维护老旧代码的的程序语言的。当谈论到对语言选择的偏好时,Rabkin 和 Meyerovich 发现年龄仅仅只代表个数字。Rabkin 告诉我说:

有一件事使我们被深深震撼到了。这事最重要的就是我们给人们按年龄分组,然后询问他们知道多少编程语言。我们主观的认为随着年龄的增长知道的会越来越多,但实际上却不是,25岁年龄组和45岁年龄组知道的语言数目是一样的。几个反复询问的问题这里持续不变的。您知道一种语言的几率并不与您的年龄挂钩。

换句话说,不仅仅年长的开发者坚持传统,年轻的程序员也会认可并采用古老的编程语言作为他们的第一们语言。这可能是因为这些语言具有很有趣的开发库及功能特点,也可能是因为在社区里开发者都是喜爱这种开发语言的一伙人。

“在全球程序员关注的语言的数量是有定数的,” Rabkin 说。“如果一们语言表现出足够独特的价值,人们将会学习和使用它。如果是和您交流代码和知识的的某个人分享一门编程语言,您将会学习它。因此,例如,只要那些 Python 库存在、 社区也对 Python 语言很有经验的话,那么 Python 仍将会大行其道。”

研究人员发现关于语言实现的功能,社区是一个巨大的因素。虽然像 Python 和 Ruby 这样的高级语言并没有太大的差别,但,程序员总是容易觉得一种比另一种优越。

“Rails 不一定要用 Ruby 语言编写,但它用了,这就是社区因素在起作用,” Rabkin 说。“例如,复活 Objective-C 语言这件事就是苹果的工程师团队说‘让我们使用它吧,’ 他们就没得选择了。”

通观社会的影响及老旧代码这些问题,我们发现最古老的和最新的计算机语言都有巨大的惰性。Go 语言怎么样才能超越 C 语言呢?如果有合适的人或公司说它超越它就超越。

“它归结为谁传播的更好谁就好,” Rabkin 说。

开始的图片来自 Blake Patterson


via: http://readwrite.com/2014/09/02/programming-language-coding-lifetime

作者:Lauren Orsini 译者:runningwater 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

诸如Apple、Facebook及Google这样的大公司正在开发他们自己的编程语言,开发者们被迫只有适应。

前不久的世界开发者大会上,Apple公布了它的新开发语言Swift。这是最近大型技术公司们开发的一大波新语言中的最新成员,这些新语言某种程度上都是专门应用于他们自己的平台。

对iOS开发者,Apple有Swift;而Facebook 有 Hack —— 一门用于后端开发的语言。与此同时,Google已经拥有了它自己的Javascript替代者 Dart,以及一门新的通用编程语言Go。

这一波又一波的新语言,给开发者们带来了许多问题。也许其中最严重的问题正如我一位同事Adriana Lee在Apple发布Swift后所说:

(开发者们到底还得学习多少门语言?) ——Adriana Lee (@adra\_la) June 2, 2014

计算机语言的通天塔

目前已经存在的编程语言有数百种,同时还有更多的语言正在涌现。其中许多都是被设计用在相对较窄的应用程序范围内,大多数甚至从未走出过项目小组的范围。

与此类似,大技术公司开发的新语言其实也是伴随着公司一起成长的。通用语言的鼻祖,C语言),就源于上世纪70年代初的AT&T贝尔实验室。Java,目前作为Android app开发的主要语言,诞生于上世纪90年代Sun公司的Microsystems系统)。

发展到现在,不同之处在于,公司们拥抱新语言、从而想要延伸的特定商业目标的范围不一样了 —— 这一过程同时建立了一个忠心耿耿的开发者基础,他们被牢牢锁定在了某个公司的特定平台上。这类一石二鸟的战略,最早可以追溯到Sun对Java的采用,当时公司就将其作为了挑战微软PC桌面统治地位的一种手段。(事情虽然没有像Sun计划的那样发展下去,但在Google转向Android之前,Java大体上也算是在企业中间件系统中找到了自己的一席之地。)

这么看来,Apple的Swift其目标也就很明确了。Swift应该不会辜负公司前期的大肆宣传,通过磨平Objective-C那粗糙的毛边,看起来它能够成功简化iOS app开发者的开发过程。但是同样还是这些开发者,他们却需要学习一门新语言的输入和输出,而这些功能很可能在其他地方都不会用到。

大公司们为什么要重复造轮子

“不要重复造轮子”这一哲学在绝大多数开发者心中根深蒂固,大公司们对此却并不买账。那他们为何不只是修改下现有语言用于新的用途呢?

答案很简单,公司们发明他们自己的语言,是因为他们有这个能力。设计一门新语言可能很复杂,但对资源要求却并不很高。困难之处也就在对其提供支持,包括提供软件资源(共享代码库、API、编译器、文档等)以及赢得开发者的支持。大公司们在这两方面尤其擅长。

还有一个事实,现有语言通常很难硬塞进如今的复杂代码框架中。举个栗子,Facebook决定发明的Hack,就是一个普遍适用于Web开发的脚本语言PHP的超集合(superset)。

Facebook的Hack最近已经比较普遍,其主要目标就是改进代码的稳定性,针对这一目的,它强制在程序运行之前对数据类型进行检测。这样的检测确保了一个程序,比方说,不会将一个整数解析为一个字符串,这样的错误如果捕获不到很可能会导致不可预知的后果。在Hack中,这些检测会预先执行,以便程序员能够在程序上线前早早发现这样的错误。

据Facebook的Hack项目组核心成员Julien Verlaguet透露,公司之前尝试过用一门现有语言实现更高效的编程。但是Facebook的大部分代码都是由PHP编写的,公司实际上已经建立了一个支持PHP及其分支的软件架构。即使能够让PHP同其他语言编写的代码协同工作,实现的难易程度和运行速度都无法满足要求。

“比如说我们尝试用Scala重写PHP代码库,”Verlaguet说。“Scala是一门设计优秀的漂亮语言,但是它与PHP完全不兼容。每次我需要从Scala的代码库部分调用PHP的时候,都会损失性能。我们很愿意使用一门现有语言,但是对于我们来说,这条路行不通。”

于是,Facebook发明了Hack,它与PHP一样能够共用公司现有的架构。Verlaguet介绍说,Facebook的代码库主体已经从PHP迁移到了Hack,同时公司将Hack开源,希望独立开发者们能够帮公司找到Facebook以外的用途。

“你仍然可以使用PHP,”他说,“但是我们希望你有使用Hack的欲望。”

谁说了算

公司和开发者之间有一种微妙的平衡。公司可以按照自己的喜好发明语言。但是如果开发者都不愿使用这门语言,那就没人用了,公司以外的人也就没人愿意将自己的职业生涯托付给这家公司。

公司在开发过程中同时使用不同的语言,这并不少见。例如,你可能用Objective-C开发iOS app,但却用Java开发Android app。对开发者来说,这从来都不是症结所在,因为Objective-C和Java都是通用面向对象语言。它们用途广泛适用于很多场合。

然而,Hack、Dart、Go和Swift,到目前为止,仍然只适用于严格特定公司的编程解决方案,往往和公司选择的编程环境相对应。诚然,现在下结论可能还太早。比方说Hack,就可以用在一些后端的实现中;它只是太新了,以至于Facebook还没有任何数据供人们如此使用。

不是开发者不能学习多门语言。事实上,大多数人已经掌握了多门语言。这好比罗曼斯语(一种由拉丁语演变而成的语言),如果你会说西班牙语,再去学法语就比那些不会西班牙语的人简单许多。与此类似,如果你已经会Java,再学Ruby或Perl就简单得多。如果你会PHP,基本上就已经学会了Hack。

与此相反,学习多门语言更多的是一个习惯问题。如果Java已经解决了你的问题,你就不再有动力去学Ruby。如果你用Objective-C编写iOS app感觉很爽,你就不会有强烈的意愿去学Swift。

另外,对于一些开发者来说,封闭生态系统的语言只会使每个人的生活变得更糟。例如,自由设计师Jack Watson-Hamblin就告诉我说,像Apple这样强势推出Swift,其实是在冒险增加程序员的负担,同时将开发者社区割裂开来:

程序员掌握多门语言固然重要,但是不断强迫他们紧跟新语言,却是行不通的。如果我正在开发一个简单的跨平台app,我可不想被迫掌握四门语言再来完成它。如果真的需要,我也只想使用一门语言。

Watson-Hamblin就主张说,当每家公司都为了自家需要发明自己的语言时,程序员的注意力被分散,开发的视野也局限于一种,这只会拖慢整个开发进程。他说,“如果拿公司负责一门语言与负责一个开源社区相比较,这两者的区别就好比一家大企业与一个初创小公司的区别”。社区生来就更加灵活,适应能力更强。

当然,Apple有许多非常好的理由推出Swift从零开始,就像当初Facebook发明Hack的时候一样。我并不是说,大公司不会强迫开发者接受这种改变,在这方面,有些公司一直都很让人讨厌。

“新语言的发明,伴随着霸权的支配,”Verlaguet说,“被迫不停追赶,确实令人沮丧,但另一方面,你又多了一种解决问题的新语言。反过来想想,要是全世界的程序员都用同样一门语言做所有事情,即使啥都凑合着能干,这门语言也一定干得不怎么样”。

题图来自于Flickr user Ruiwen Chua,CC 2.0


via: http://readwrite.com/2014/06/17/apple-swift-facebook-hack-google-dart

译者:Mr小眼儿 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

简介

PHP是一门复杂的语言,经过多年折腾,使其不同版本之间高度不一致,有时还有些bug。 每个版本都有自己独有的特性、多余和怪异之处,也很难跟踪哪个版本有哪些问题。这也就 很好理解为什么有时它会遭到那么多的厌恶。

尽管如此,如今它还是Web开发方面最流行的语言。因其悠久的历史,对于实现密码哈希和 数据库访问诸如此类的基本任务你能够找到很多教程。但问题在于,5个教程,你就很有可能 找到5种完全不同的完成任务的方式,那么哪种是“正确”的方式呢?其他方式有难以捉摸的bug 或者陷阱?确实很难搞明白,所以你经常要在互联网上反复查找尝试确认正确的答案。

这也是PHP编程新手频繁地因为丑陋、过时、或不安全的代码而遭到责备的原因之一。如果 Google搜索的第一个结果是一篇4年前的文章,讲述一种5年前的方法,那么PHP新手们也就 很难改变经常遭受责备的现状。

本文档通过为PHP中常见的令人困惑的问题和任务编辑组织一系列被认为最佳实践的基本做法, 来尝试解决上述问题。若一个低层次的任务在PHP中有多种令人困惑的实现方式,本文也会涵盖。

是什么

这是一份指南,在PHP程序员遇到一些常见低层次任务但不明确最佳做法(由于PHP可能提供 了多种解决方案)之时,为其建议最佳实践。例如:连接数据库是一个常见任务,PHP中提供了 大量可行的方案,但并不是所有的都是好的做法,因此,本文也会包含该问题。

本文包含的是一系列简短的、入门性质的方案。涉及的示例在基本设定下就能够运行起来, 你研究一下应该就能把它们变为对你有用的东西。

本文将指出一些我们认为是PHP中最新最好的东西。然而,这意味如果你在使用老版本的PHP, 一些用来实现这些解决方案的特性对你并不可用。

这份文档会一直更新,我会尽我最大努力保持该文档与PHP的发展同步。

不是什么

本文档不是一份PHP教程。你应该在别处学习语言基础和语法。

它也不是一份针对web应用常见问题,如cookie存储、缓存、编程风格、文档等的指南。

它也不是一个安全指南。当本文档触碰到一些安全相关的问题时,也是希望你自己做些研究来 确保你的PHP应用的安全问题。你的代码造成的问题应该都是自己的过错。

该文档也并不是在主张一种特定的编程风格、模式或者框架。

也不是在主张一种特定的方式来完成高层次任务如用户注册、登录系统等。本文档只限于 PHP的悠久历史所造成的一些易混淆或不明确的低层次任务。

它不是一个一劳永逸的解决方案,也不是一个唯一的方案。下面要讲述的一些方法对于你的 特定场景来说也许并不是最好的,存在很多不同的方式来达到同样的目的。特别是,高负载web 应用也许能从更加难懂的方案中获益更多。

我们在使用哪个版本的PHP?

带Suhosin-Patch的PHP 5.3.10-1ubuntu3.6,安装在Ubuntu 12.04 LTS上。

PHP是Web世界里的百年老龟,它的壳上铭刻着一段丰富、复杂、而粗糙的历史。在一个共享 主机的环境里,它的配置可能会限制你能做的事情。

为了保持清晰地叙述,我们将仅针对一个版本的PHP进行讲述。在2013年4月30日时,该版本 为PHP 5.3.10-1ubuntu3.6 with Suhosin-Patch。若你在Ubuntu 12.04 LTS服务器 上使用apt-get进行安装的就是该版本的PHP。

你也许发现这些方案中的一些在其他或者更老版本的PHP上也能工作。如果是这样的话,就由 你来研究在这些更老版本上潜在的难以捉摸的bug或安全问题

存储密码

使用phpass库来哈希和比较密码

经phpass 0.3测试

在存入数据库之前进行哈希保护用户密码的标准方式。许多常用的哈希算法如md5,甚至是sha1 对于密码存储都是不安全的,因为骇客能够使用那些算法轻而易举地破解密码

对密码进行哈希最安全的方法是使用bcrypt算法。开源的phpass库以一个易于使用的类来提供 该功能。

示例

HashPassword('my super cool password');

// You can now safely store the contents of $hashedPassword in your database!

// Check if a user has provided the correct password by comparing what they
// typed with our hash
$hasher->CheckPassword('the wrong password', $hashedPassword);  // false

$hasher->CheckPassword('my super cool password', $hashedPassword);  // true
?>

陷阱

  • 许多资源可能推荐你在哈希之前对你的密码“加盐”。想法很好,但phpass在HashPassword()函数中已经对你的密码“加盐”了,这意味着你不需要自己“加盐”。

进一步阅读

连接并查询MySQL数据库

使用PDO及其预处理语句功能。

在PHP中,有很多方式来连接到一个MySQL数据库。PDO(PHP数据对象)是其中最新且最健壮的一种。PDO跨多种不同类型数据库有一个一致的接口,使用面向对象的方式,支持更多的新数据库支持的特性。

你应该使用PDO的预处理语句函数来帮助防范SQL注入攻击。使用函数bindValue来确保你的SQL免于一级SQL注入攻击。(虽然并不是100%安全的,查看进一步阅读获取更多细节。)在以前,这必须使用一些“魔术引号(magic quotes)”函数的组合来实现。PDO使得那堆东西不再需要。

示例

 \PDO::ERRMODE_EXCEPTION, 
                            \PDO::ATTR_PERSISTENT => false, 
                            \PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'
                        )
                    );
 
    $handle = $link->prepare('select Username from Users where 
         UserId = ? or Username = ? limit ?');
 
    // PHP bug: if you don't specify PDO::PARAM_INT, PDO may enclose
    //  the argument in quotes.
    // This can mess up some MySQL queries that don't expect integers 
    // to be quoted.
    // See: https://bugs.php.net/bug.php?id=44639
    // If you're not sure whether the value you're passing is an integer, 
    // use the is_int() function.
    $handle->bindValue(1, 100, PDO::PARAM_INT);
    $handle->bindValue(2, 'Bilbo Baggins');
    $handle->bindValue(3, 5, PDO::PARAM_INT);
 
    $handle->execute();
 
    // Using the fetchAll() method might be too resource-heavy if you're 
    // selecting a truly massive amount of rows.
    // If that's the case, you can use the fetch() method and loop through 
    // each result row one by one.
    // You can also return arrays and other things instead of objects.  See
    //  the PDO documentation for details.
    $result = $handle->fetchAll(\PDO::FETCH_OBJ);
 
    foreach($result as $row){
        print($row->Username);
    }
}
catch(\PDOException $ex){
    print($ex->getMessage());
}
?>

陷阱

  • 当绑定整型变量时,如果不传递PDO::PARAM\_INT参数有事可能会导致PDO对数据加引号。这会 搞坏特定的MySQL查询。查看该bug报告
  • 未使用 set names utf8mb4 作为首个查询,可能会导致Unicode数据错误地存储进数据库,这依赖于你的配置。如果你 绝对有把握你的Unicode编码数据不会出问题,那你可以不管这个。
  • 启用持久连接可能会导致怪异的并发相关的问题。这不是一个PHP的问题,而是一个应用层面 的问题。只要你仔细考虑了后果,持久连接一般会是安全的。查看Stack Overfilow这个问题
  • 即使你使用了 set names utf8mb4 ,你也得确认实际的数据库表使用的是utf8mb4字符集!
  • 可以在单个execute()调用中执行多条SQL语句。只需使用分号分隔语句,但注意这个bug,在该文档所针对的PHP版本中还没修复。

进一步阅读

PHP标签

使用 。

有几种不同的方式用来区分PHP程序块:, , , 以及。对于打字来说,更短的标签更方便些,但唯一一种在所有PHP服务器上都一定能工作的标签 是。若你计划将你的PHP应用部署到一台上面的PHP配置你无法控制的服务器上,那么你应始终使用 。

若你仅仅是为自己编码,也能控制你将使用的PHP配置,你可能觉得短标签更方便些。但记住 可能会和XML声明冲突,并且实际上是ASP的风格。

无论你选择哪一种,确保一致。

陷阱

  • 在一个纯PHP文件(例如,仅包含一个类定义的文件)中包含一个关闭?>标签时,确保其后 不会跟着任何换行。当PHP解析器安全地吃进跟在关闭标签之后的单个换行符时,任何其他的换行 都可能被输出到浏览器,如果之后要输出某些HTTP头,那么可能会造成混淆。
  • 编写Web应用时,确保在关闭?>标签与html的标签之间不会留下换行。正确的HTML 文件中,标签必须是文件中的第一样东西—在其之前的任何空格或换行都会使其 无效。

进一步阅读

自动加载类

使用spl\_autoload\_register()来注册你的自动加载函数。

PHP提供了若干方式来自动加载包含还未加载的类的文件。老的方法是使用名为\_\_autoload()魔术全局函数。然而你一次仅能定义一个\_\_autoload()函数,因此如果你的程序 包含一个也使用了\_\_autoload()函数的库,就会发生冲突。

处理这个问题的正确方法是唯一地命名你的自动加载函数,然后使用spl\_autoload\_register()函数 来注册它。该函数允许定义多个\_\_autoload()这样的函数,因此你不必担心其他代码的\_\_autoload()函数。

示例

进一步阅读

从性能角度来看单引号和双引号

其实并不重要。

已有很多人花费很多笔墨来讨论是使用单引号(')还是双引号(")来定义字符串。 单引号字符串不会被解析,因此放入字符串的任何东西都会以原样显示。双引号字符串会被解析, 字符串中的任何PHP变量都会被求值。另外,转义字符如换行符\n和制表符\t在单引号字符串中 不会被求值,但在双引号字符串中会被求值。

由于双引号字符串在程序运行时要求值,从而理论上使用单引号字符串能提高性能,因为PHP 不会对单引号字符串求值。这对于一定规模的应用来说也许确实如此,但对于现实中一般的应用来说, 区别非常小以至于根本不用在意。因此对于普通应用,你选择哪种字符串并不重要。对于负载 极其高的应用来说,是有点作用的。根据你的应用的需要来做选择,但无论你选择什么,请保持一致。

进一步阅读

define() vs. const

使用define(),除非考虑到可读性、类常量、或关注微优化

习惯上,在PHP中是使用define()函数来定义常量。但从某个时候开始,PHP中也能够使用const 关键字来声明常量了。那么当定义常量时,该使用哪种方式呢?

答案在于这两种方法之间的区别。

  1. define()在执行期定义常量,而const在编译期定义常量。这样const就有轻微的速度优势, 但不值得考虑这个问题,除非你在构建大规模的软件。
  2. define()将常量放入全局作用域,虽然你可以在常量名中包含命名空间。这意味着你不能 使用define()定义类常量。
  3. define()允许你在常量名和常量值中使用表达式,而const则都不允许。这使得define() 更加灵活。
  4. define()可以在if()代码块中调用,但const不行。

示例

因为define()更加灵活,你应该使用它以避免一些令人头疼的事情,除非你明确地需要类 常量。使用const通常会产生更加可读的代码,但是以牺牲灵活性为代价的。

无论你选择哪一种,请保持一致。

进一步阅读

缓存PHP opcode

使用APC

在一个标准的PHP环境中,每次访问PHP脚本时,脚本都会被编译然后执行。一次又一次地花费 时间编译相同的脚本对于大型站点会造成性能问题。

解决方案是采用一个opcode缓存。opcode缓存是一个能够记下每个脚本经过编译的版本,这样 服务器就不需要浪费时间一次又一次地编译了。通常这些opcode缓存系统也能智能地检测到 一个脚本是否发生改变,因此当你升级PHP源码时,并不需要手动清空缓存。

有几个PHP opcode缓存可用,其中值得关注的有eacceleratorxcache,以及APC。 APC是PHP项目官方支持的,最为活跃,也最容易安装。它也提供一个可选的类memcached 的持久化键-值对存储,因此你应使用它。

安装APC

在Ubuntu 12.04上你可以通过在终端中执行以下命令来安装APC:

user@localhost: sudo apt-get install php-apc

除此之外,不需要进一步的配置。

将APC作为一个持久化键-值存储系统来使用

APC也提供了对于你的脚本透明的类似于memcached的功能。与使用memcached相比一个大的优势是 APC是集成到PHP核心的,因此你不需要在服务器上维护另一个运行的部件,并且PHP开发者在APC 上的工作很活跃。但从另一方面来说,APC并不是一个分布式缓存,如果你需要这个特性,你就 必须使用memcached了。

示例

陷阱

  • 如果你使用的不是PHP-FPM(例如你在 使用mod\_phpmod\_fastcgi),那么 每个PHP进程都会有自己独有的APC实例,包括键-值存储。若你不注意,这可能会在你的应用 代码中造成同步问题。

进一步阅读

PHP与Memcached

若你需要一个分布式缓存,那就使用Memcached客户端库。否则,使用APC。

缓存系统通常能够提升应用的性能。Memcached是一个受欢迎的选择,它能配合许多语言使用, 包括PHP。

然而,从一个PHP脚本中访问一个Memcached服务器,你有两个不同且命名很愚蠢的客户端库选择项:MemcacheMemcached。 它们是两个名字几乎相同的不同库,两者都可用于访问一个Memcached实例。

事实证明,Memcached库对于Memcached协议的实现最好,包含了一些Mmecache库没有的有用的特性, 并且看起来Memcached库的开发也最为活跃。

然而,如果不需要访问来自一组分布式服务器的一个Memcached实例,那就使用APC。 APC得到PHP项目的支持,具备很多和Memcached相同的功能,并且能够用作opcode缓存,这能提高PHP脚本的性能。

安装Memcached客户端库

在安装Memcached服务器之后,需要安装Memcached客户端库。没有该库,PHP脚本就没法与 Memcached服务器通信。

在Ubuntu 12.04上,你可以使用如下命令来安装Memcached客户端库:

user@localhost: sudo apt-get install php5-memcached

使用APC作为替代

查看opcode缓存一节阅读更多与使用APC作为 Memcached替代方案相关的信息。

进一步阅读

PHP与正则表达式

使用PCRE(preg\_*)家族函数

PHP有两种使用不同的方式来使用正则表达式:PCRE(Perl兼容表示法,preg\_*)函数 和POSIX(POSIX扩展表示法,ereg\_*) 函数。

每个函数家族各自使用一种风格稍微不同的正则表达式。幸运的是,POSIX家族函数从PHP 5.3.0开始就被弃用了。因此,你绝不应该使用POSIX家族函数编写新的代码。始终使用 PRCE家族函数,即preg\_*函数。

进一步阅读

配置Web服务器提供PHP服务

使用PHP-FPM

有多种方式来配置一个web服务器以提供PHP服务。传统(并且糟糕的)的方式是使用Apache的 mod\_php。Mod\_php将PHP 绑定到Apache自身,但是Apache对于该模块功能的管理工作非常糟糕。一旦遇到较大的流量, 就会遭受严重的内存问题。

后来两个新的可选项很快流行起来:mod\_fastcgimod\_fcgid。两者均保持一定数量的PHP执行进程, Apache将请求发送到这些端口来处理PHP的执行。由于这些库限制了存活的PHP进程的数量, 从而大大减少了内存使用而没有影响性能。

一些聪明的人创建一个fastcgi的实现,专门为真正与PHP工作良好而设计,他们称之为 PHP-FPM。PHP 5.3.0之前,为安装它, 你得跨越许多障碍,但幸运的是,PHP 5.3.3的核心包含了PHP-FPM,因此在Ubuntu 12.04上安装它非常方便。

如下示例是针对Apache 2.2.22的,但PHP-FPM也能用于其他web服务器如Nginx。

安装PHP-FPM和Apache

在Ubuntu 12.04上你可以使用如下命令安装PHP-FPM和Apache:

user@localhost: sudo apt-get install apache2-mpm-worker
libapache2-mod-fastcgi php5-fpm
user@localhost: sudo a2enmod actions alias fastcgi

注意我们必须使用apache2-mpm-worker,而不是apache2-mpm-prefork或apache2-mpm-threaded。

接下来配置Aapache虚拟主机将PHP请求路由到PHP-FPM进程。将如下配置语句放入Apache 配置文件(在Ubuntu 12.04上默认配置文件是/etc/apache2/sites-available/default)。

    AddHandler php5-fcgi .php
    Action php5-fcgi /php5-fcgi
    Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
    FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:9000 -idle-timeout 120 -pass-header Authorization

最后,重启Apache和FPM进程:

user@localhost: sudo service apache2 restart && sudo service php5-fpm
restart

进一步阅读

发送邮件

使用PHPMailer

经PHPMailer 5.1测试

PHP提供了一个mail()函数,看起来很简单易用。 不幸的是,与PHP中的很多东西一样,它的简单性是个幻象,因其虚假的表面使用它会导致 严重的安全问题。

Email是一组网络协议,比PHP的历史还曲折。完全可以说发送邮件中的陷阱与PHP的mail() 函数一样多,这个可能会令你有点“不寒而栗”吧。

PHPMailer是一个流行而 成熟的开源库,为安全地发送邮件提供一个易用的接口。它关注可能陷阱,这样你可以专注 于更重要的事情。

示例

Sender = '[email protected]';
$mailer->AddReplyTo('[email protected]', 'Bilbo Baggins');
$mailer->SetFrom('[email protected]', 'Bilbo Baggins');
$mailer->AddAddress('[email protected]');
$mailer->Subject = 'The finest weed in the South Farthing';
$mailer->MsgHTML('

You really must try it, Gandalf!

-Bilbo

');
 
// Set up our connection information.
$mailer->IsSMTP();
$mailer->SMTPAuth = true;
$mailer->SMTPSecure = 'ssl';
$mailer->Port = 465;
$mailer->Host = 'my smpt host';
$mailer->Username = 'my smtp username';
$mailer->Password = 'my smtp password';
 
// All done!
$mailer->Send();
?>

验证邮件地址

使用filter\_var()函数

Web应用可能需要做的一件常见任务是检测用户是否输入了一个有效的邮件地址。毫无疑问 你可以在网上找到一些声称可以解决该问题的复杂的正则表达式,但是最简单的方法是使用 PHP的内建filter\_val()函数。

示例

进一步阅读

净化HTML输入和输出

对于简单的数据净化,使用htmlentities()函数, 复杂的数据净化则使用HTML Purifier

经HTML Purifier 4.4.0测试

在任何wbe应用中展示用户输出时,首先对其进行“净化”去除任何潜在危险的HTML是非常必要的。 一个恶意的用户可以制作某些HTML,若被你的web应用直接输出,对查看它的人来说会很危险。

虽然可以尝试使用正则表达式来净化HTML,但不要这样做。HTML是一种复杂的语言,试图 使用正则表达式来净化HTML几乎总是失败的。

你可能会找到建议你使用strip\_tags() 函数的观点。虽然strip\_tags()从技术上来说是安全的,但如果输入的不合法的HTML(比如, 没有结束标签),它就成了一个“愚蠢”的函数,可能会去除比你期望的更多的内容。由于非技术用户 在通信中经常使用<和>字符,strip\_tags()也就不是一个好的选择了。

如果阅读了验证邮件地址一节, 你也许也会考虑使用filter\_var() 函数。然而filter\_var()函数在遇到断行时会出现问题, 并且需要不直观的配置以接近htmlentities()函数的效果, 因此也不是一个好的选择。

对于简单需求的净化

如果你的web应用仅需要完全地转义(因此可以无害地呈现,但不是完全去除)HTML,则使用 PHP的内建htmlentities()函数。 这个函数要比HTML Purifier快得多,因此它不对HTML做任何验证—仅转义所有东西。

htmlentities()不同于类似功能的函数htmlspecialchars(), 它会编码所有适用的HTML实体,而不仅仅是一个小的子集。

示例

Mua-ha-ha!  Twiddling my evil mustache...

'; // Use the ENT\_QUOTES flag to make sure both single and double // quotes are escaped. // Use the UTF-8 character encoding if you've stored the text as // UTF-8 (as you should have). // See the UTF-8 section in this document for more details. $safeHtml = htmlentities($evilHtml, ENT\_QUOTES, 'UTF-8'); // $safeHtml is now fully escaped HTML. You can output $safeHtml // to your users without fear! ?>

对于复杂需求的净化

对于很多web应用来说,简单地转义HTML是不够的。你可能想完全去除任何HTML,或者允许 一小部分子集的HTML存在。若是如此,则使用HTML Purifier 库。

HTML Purifier是一个经过充分测试但效率比较低的库。这就是为什么如果你的需求并不复杂 就应使用htmlentities(),因为 它的效率要快得多。

HTML Purifier相比strip\_tags() 是有优势的,因为它在净化HTML之前会对其校验。这意味着如果用户输入无效HTML,HTML Purifier相比strip\_tags()更能保留HTML的原意。HTML Purifier高度可定制,允许你为HTML的一个子集建立白名单来允许这个HTML子集的实体存在 输出中。

但其缺点就是相当的慢,它要求一些设置,在一个共享主机的环境里可能是不可行的。其文档 通常也复杂而不易理解。以下示例是一个基本的使用配置。查看文档 阅读HTML Purifier提供的更多更高级的特性。

示例

Mua-ha-ha!  Twiddling my evil mustache...';
 
// Set up the HTML Purifier object with the default configuration.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
 
$safeHtml = $purifier->purify($evilHtml);
// $safeHtml is now sanitized.  You can output $safeHtml to your 
// users without fear!
?>

陷阱

  • 以错误的字符编码使用htmlentities()会造成意想不到的输出。在调用该函数时始终确认 指定了一种字符编码,并且该编码与将被净化的字符串的编码相匹配。更多细节请查看 UTF-8一节
  • 使用htmlentities()时,始终包含ENT\_QUOTES和字符编码参数。默认情况下,htmlentities() 不会对单引号编码。多愚蠢的默认做法!
  • HTML Purifier对于复杂的HTML效率极其的低。可以考虑设置一个缓存方案如APC来保存经过净化的结果 以备后用。

进一步阅读

PHP与UTF-8

没有一行式解决方案。小心、注意细节,以及一致性。

PHP中的UTF-8糟透了。原谅我的用词。

目前PHP在低层次上还不支持Unicode。有几种方式可以确保UTF-8字符串能够被正确处理, 但并不容易,需要深入到web应用的所有层面,从HTML,到SQL,到PHP。我们旨在提供一个简洁、 实用的概述。

PHP层面的UTF-8

基本的字符串操作,如串接 两个字符串、将字符串赋给变量,并不需要任何针对UTF-8的特殊东西。然而,多数 字符串函数,如strpos()strlen,就需要特殊的考虑。这些 函数都有一个对应的mb\_*函数:例如,mb\_strpos()mb\_strlen()。这些对应的函数 统称为多字节字符串函数。这些多字节字符串 函数是专门为操作Unicode字符串而设计的。

当你操作Unicode字符串时,必须使用mb\_*函数。例如,如果你使用substr() 操作一个UTF-8字符串,其结果就很可能包含一些乱码。正确的函数应该是对应的多字节函数, mb\_substr()

难的是始终记得使用mb\_*函数。即使你仅一次忘了,你的Unicode字符串在接下来的处理中 就可能产生乱码。

并不是所有的字符串函数都有一个对应的mb\_*。如果不存在你想要的那一个,那你就只能 自认倒霉了。

此外,在每个PHP脚本的顶部(或者在全局包含脚本的顶部)你都应使用 mb\_internal\_encoding 函数,如果你的脚本会输出到浏览器,那么还得紧跟其后加个mb\_http\_output() 函数。在每个脚本中显式地定义字符串的编码在以后能为你减少很多令人头疼的事情。

最后,许多操作字符串的PHP函数都有一个可选参数让你指定字符编码。若有该选项, 你应 始终显式地指明UTF-8编码。例如,htmlentities() 就有一个字符编码方式选项,在处理这样的字符串时应始终指定UTF-8。

MySQL层面的UTF-8

如果你的PHP脚本会访问MySQL,即使你遵从了前述的注意事项,你的字符串也有可能在数据库 中存储为非UTF-8字符串。

确保从PHP到MySQL的字符串为UTF-8编码的,确保你的数据库以及数据表均设置为utf8mb4字符集, 并且在你的数据库中执行任何其他查询之前先执行MySQL查询set names utf8mb4。这是至关重要的。示例 请查看连接并查询MySQL数据库一节内容。

注意你必须使用utf8mb4字符集来获得完整的UTF-8支持,而不是utf8字符集!原因 请查看进一步阅读

浏览器层面的UTF-8

使用mb\_http\_output()函数 来确保你的PHP脚本输出UTF-8字符串到浏览器。并且在HTML页面的标签块中包含字符集标签块

示例

 \PDO::ERRMODE_EXCEPTION,
                        \PDO::ATTR_PERSISTENT => false,
                        \PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'
                    )
                );
     
// Store our transformed string as UTF-8 in our database
// Assume our DB and tables are in the utf8mb4 character set and collation
$handle = $link->prepare('insert into Sentences (Id, Body) values (?, ?)');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->bindValue(2, $string);
$handle->execute();
 
// Retrieve the string we just stored to prove it was stored correctly
$handle = $link->prepare('select * from Sentences where Id = ?');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->execute();
    
// Store the result into an object that we'll output later in our HTML
$result = $handle->fetchAll(\PDO::FETCH_OBJ);
?>UTF-8 test pageBody);  
            // This should correctly output our transformed UTF-8 string to the browser
        }
        ?>

进一步阅读

处理日期和时间

使用DateTime类

在PHP糟糕的老时光里,我们必须使用date()gmdate()date\_timezone\_set()strtotime()等等令人迷惑的 组合来处理日期和时间。悲哀的是现在你仍旧会找到很多在线教程在讲述这些不易使用的老式函数。

幸运的是,我们正在讨论的PHP版本包含友好得多的DateTime类。 该类封装了老式日期函数所有功能,甚至更多,在一个易于使用的类中,并且使得时区转换更加容易。 在PHP中始终使用DateTime类来创建,比较,改变以及展示日期。

示例

add(new DateInterval('P10D'));
 
echo($date->format('Y-m-d h:i:s')); // 2011-05-14 05:00:00
 
// Sadly we don't have a Middle Earth timezone
// Convert our UTC date to the PST (or PDT, depending) time zone
$date->setTimezone(new DateTimeZone('America/Los_Angeles'));
 
// Note that if you run this line yourself, it might differ by an 
// hour depending on daylight savings
echo($date->format('Y-m-d h:i:s')); // 2011-05-13 10:00:00
 
$later = new DateTime('2012-05-20', new DateTimeZone('UTC'));
 
// Compare two dates
if($date < $later)
    echo('Yup, you can compare dates using these easy operators!');
 
// Find the difference between two dates
$difference = $date->diff($later);
 
echo('The 2nd date is ' . $difference['days'] . ' later than 1st date.');
?>

陷阱

  • 如果你不指定一个时区,DateTime::\_\_construct() 就会将生成日期的时区设置为正在运行的计算机的时区。之后,这会导致大量令人头疼的事情。 在创建新日期时始终指定UTC时区,除非你确实清楚自己在做的事情。
  • 如果你在DateTime::\_\_construct()中使用Unix时间戳,那么时区将始终设置为UTC而不管 第二个参数你指定了什么。
  • 向DateTime::\_\_construct()传递零值日期(如:“0000-00-00”,常见MySQL生成该值作为 DateTime类型数据列的默认值)会产生一个无意义的日期,而不是“0000-00-00”。
  • 在32位系统上使用DateTime::getTimestamp() 不会产生代表2038年之后日期的时间戳。64位系统则没有问题。

进一步阅读

检测一个值是否为null或false

使用===操作符来检测null和布尔false值。

PHP宽松的类型系统提供了许多不同的方法来检测一个变量的值。然而这也造成了很多问题。 使用==来检测一个值是否为null或false,如果该值实际上是一个空字符串或0,也会误报 为false。isset是检测一个变量是否有值, 而不是检测该值是否为null或false,因此在这里使用是不恰当的。

is\_null()函数能准确地检测一个值 是否为null,is\_bool可以检测一个值 是否是布尔值(比如false),但存在一个更好的选择:===操作符。===检测两个值是否同一, 这不同于PHP宽松类型世界里的相等。它也比is\_null()和is\_bool()要快一些,并且有些人 认为这比使用函数来做比较更干净些。

示例

陷阱

  • 测试一个返回0或布尔false的函数的返回值时,如strpos(),始终使用===和!==,否则 你就会碰到问题。

进一步阅读

建议与指正

感谢阅读!如果你有些地方还不太理解,很正常,PHP是复杂的,并且充斥着陷阱。因为我也 只是一个人,所以本文档中难免存在错误。

如果你想为本文档贡献建议或纠正错误之处,请使用最后修订日期&维护者 一节中的信息联系我。

原文: PHP Best Practices-A short, practical guide for common and confusing PHP tasks

译者:youngsterxyf