PHP40个有用建议
时间:2014-5-4 作者:smarteng 分类: PHP相关
在这个系列中我们将看到一些有用的小贴士和技术来提升和优化你得php代码。请注意这些php小贴士对初学者是有意义的,而不是哪些已经在用mvc框架的人。
1.不要使用相对路径,以定义根路径代替
这样的代码行是很常见的:
1 require_once('../../lib/some_class.php');
这种做法有很多弊端:
它首先查找php的include_path中定义的目录,然后才从当前目录查找。因此检查了很多目录。
当一个脚本被另一个脚本包含在不同的目录中,它的基础路径变为了那个包含的脚本所在的位置。
另一个问题是,当一个脚本是从cron启动的,它可能找不到父目录作为工作目录。
因此用绝对路径是个好主意:
1 define('ROOT','/var/www/project');
2 require_once(ROOT . '../../lib/some_class.php');
3
4 //代码剩余部分
现在这是个绝对路径了并且会保持不变。但是我们可以改进更多。/var/www/project这个目录要是变了,难道我们每次都去修改它吗?不。相反,我们通过使用FILE这样的魔法常量来使它更方便。仔细看看:
1 //假设脚本为 /var/www/project/index.php
2 //那么__FILE__ 会试那个完整路径
3
4 define('ROOT', pathinfo(__FILE__, PATHINFO_DIRNAME));
5 require_once(ROOT . '../../lib/some_class.php');
6
7 //代码剩余部分
因此现在即使你把你的工程移到别的目录,比如移到线上服务器,同样的代码也可以不做任何改变就运行良好。
2.不要使用require,include,require_once或者include_ince
你的脚本也许会在顶部包含不同的文件,诸如像这样的类库、公用函数和辅助函数等等:
1 require_once('lib/Datavase.php');
2 require_once('lib/Mail.php');
3
4 require_once('helpers/utitlity_functions.php');
这是十分粗糙的。代码需要更加灵活些。详细写些辅助函数来更容易地包含文件。举个例子:
1 function load_class($class_name){
2 //类文件的路径
3 $path = ROOT . '/lib' . $class_name . '.php';
4 require_once( $path );
5 }
6
7 load_class('Database');
8 load_class('Mail');
看到不同之处了吗?你肯定看到了。不需要更多解释了。
你可以改得更好如果你愿意这样的话:
1 function load_class($class_name){
2 //类文件的路径
3 $path = ROOT . '/lib' . $class_name . '.php';
4
5 if (file_exists($path)){
6 require_once($path);
7 }
8 }
利用这点可以做很多事情:
- 为同一个类文件查找多个目录。
- 改变包含类文件的目录很容易,并且不会在任何地方破坏代码。
- 使用类似的函数来加载包含辅助函数或是html内容等文件。
3.在应用中维护调试环境
在开发期间我们会输出数据库查询语句,或是打印出问题的变量,然后等到问题被解决了,我们会把他们注释掉或是删掉。但是长期来说保留一切会有帮助。
在你的开发机上你可以这样做:
1 define('ENVIRONMENT' , 'development');
2
3 if (! $db->query( $query )){
4 if (ENVIRONMENT == 'development'){
5 echo "$query failed";
6 }
7 else{
8 echo "Database error. Please contact administrator";
9 }
10 }
然后服务器上你可以这么做:
1 define('ENVIRONMENT' , 'production');
2
3 if (! $db->query( $query )){
4 if (ENVIRONMENT == 'development'){
5 echo "$query failed";
6 }
7 else{
8 echo "Database error. Please contact administrator";
9 }
10 }
4.通过会话(session)来传递状态信息
状态信息是指做完一个任务后产生的信息。
1 <?php
2 if ($wrong_username || $wrong_password){
3 $msg = 'Invalid username or password';
4 }
5 ?>
6 <html>
7 <body>
8
9 <?php echo $msg;?>
10
11 <form>
12 ...
13 </form>
14 </body>
15 </html>
这样的代码是很常见的。使用变量来说明状态信息有局限性。他们不能通过重定向被传送(除非你把他们当做GET变量传到下一个脚本,但这样是很愚蠢的)。在大型脚本中,可能会有许多的信息。
最好的方法是使用会话来传递他们(即使在同一个页面)。对于这种情况,需要在每个页面有个session_start。
1 function set_flash($msg){
2 $_SESSION['message'] = $msg;
3 }
4
5 function get_flash(){
6 $msg = $_SESSION['message'];
7 unset($_SESSION['message']);
8 return $msg;
9 }
脚本如下:
1 <?php
2 if ($wrong_username || $wrong_password){
3 set_flash('Invalid username or password');
4 }
5 ?>
6 <html>
7 <body>
8
9 status is : <?php echo get_flash(); ?>
10 <form>
11 ...
12 </form>
13 </body>
14 </html>
5.让你的函数更灵活
1 function add_to_cart($item_id,$qty){
2 $_SESSION['cart'][$item_id] = $qty;
3 }
4
5 add_to_cart( 'IPHONE3' , 2);
当要添加一个物品时你可以用上面的函数。当要添加多个物品时,你会创建另一个函数吗?不用。只要让函数灵活到能够接受不同类别的参数就行了。下面仔细看看:
1 function add_to_cart($item , $qty){
2 if (!is_array($item_id)){
3 $_SESSION['cart'][$item_id] = $qty;
4 }
5 else{
6 foreach ($item_is as $i_id=>$qty){
7 $_SESSION['cart'][$i_id] = $qty;
8 }
9 }
10 }
11
12 add_to_cart( 'IPHONE3' ,2);
13 add_to_cart( array('IPHONE3'=>2,'IPAD'=>5));
所以现在同一个函数可以接受不同类别的输入。上面的方法可以在许多地方应用来让你的代码更敏捷。
6.省略php闭合标签如果代码在这结束
我好奇为什么这条贴士在如此多的关于php贴士的博文中被忽略了。
1 <?php
2 echo "Hello";
3
4 // Now dont close this tag
这将节省你大量的问题。来看个例子:
类文件super_class.php
1 <?php
2 class super_class{
3 function super_function(){
4 //super code
5 }
6 }
7 ?>
8 //super extra character after the closing tag
index.php
1 require_once('super_class.php');
2
3 //echo an image or pdf, or set the cookies or session data
现在你会得到“Headers already send error”错误。为什么呢?因为“super extra character”被打印出来了,然后所有的头部跟在那后面。现在你开始调试。你可能会浪费很多时间来找出这个位置。
因此把省略闭合标签作为习惯吧:
1 <?php
2 class super_class{
3 function super_function(){
4 //super code
5 }
6 }
7
8 //No closing tag
这样好多了
7.在同一个地方收集所有输出,并且一次输出到浏览器上
这就是所谓的输出缓冲。假设你已经像这样从不同的函数输出内容:
1 function print_header(){
2 echo "<div id='header'>Site Log and Login links</div>";
3 }
4 function print_footer(){
5 echo "<div id='footer'>Site was made by me</div>";
6 }
7
8 print_header();
9 for ($i = 0l $i < 100; $i++){
10 echo "I is : $i <br />";
11 }
12 print_footer();
代替那样做,首先收集所有的输出在一个位置。你可以在函数中把它存到变量里,也可以用ob_start和ob_end_clean。因此现在看起来是这样的
1 function print_header(){
2 $o = "<div id='header'>Site Log and Login links</div>";
3 return $o;
4 }
5
6 function print_footer(){
7 $o = "<div id='footer'>Site was made by me</div>";
8 return $o;
9 }
10
11 echo print_header();
12 for ($i = 0; $i < 100; $i++){
13 echo "I is : $i <br />";
14 }
15 echo print_footer();
因此你应该做输出缓冲的理由是:
- 如果你需要的话你能在传到浏览器之前修改输出内容。考虑下做一些str_replace操作,或者是preg_replace操作,或者是添加一些额外的html到末尾,比如分析器/调试器输出
- 发送输出到浏览器的同时也做php处理是个糟糕的想法。你是否曾见过出现在侧边栏或是屏幕中间的盒子里的Fatal error。你知道为什么会这样吗?因为处理和输出混在一起了。
8.输出非html内容时通过header发送正确地MIME type
我们输出一些xml试试。
1 $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
2 $xml = "<response>
3 <code>0</code>
4 </response>";
5
6 //Send xml data
7 echo $xml;
完好运行。但是这需要一些改进。
1 $xml = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
2 $xml = "<response>
3 <code>0</code>
4 </response>";
5
6 //Send xml data
7 header("content-type: text/xml");
8 echo $xml;
注意看header那一行。那一行告诉浏览器这是xml内容。所以浏览器能正确处理它。许多js库也依赖头部信息。
对js,css,jps,png是类似的:
Javascript
1 header("content-type:application/x-javascript");
2 echo "var a = 10";
1 header("content-type: text/css");
2 echo "#div id {background:#000; }";
9.为mysql链接设置正确地编码
曾近遇上过这样一个问题,mysql表里正确地存储着unicode/utf-8编码的数据,phpmyadmin也显示正确,但是当你获取他们并把他们输出到你的页面上,他们并没有正确显示。秘密在于mysql的连接字符编码。
1 $host = 'localhost';
2 $username = 'root';
3 $password = 'super_secret';
4
5 //尝试连接到数据库
6 $c = mysqli_connect($host , $username , $password);
7
8 //检查连接有效性
9 if (!$c){
10 die("Could not connect to the database host: <br>" . mysqli_connect_error());
11 }
12
13 //设置连接的字符集
14 if (!mysqli_set_charset( $c , 'UTF8' )){
15 die('mysqli_set_charset() failed');
16 }
一旦你连接到数据库,设置连接的字符集是个好主意。当你在应用中处理多种语言时这么做是必须得。
否则会发生什么?你会在非英语文本看到许多方块和????????。
10.用正确的字符集选项使用htmlentities
在php 5.4之前,默认的字符编码用的是ISO-8859-1,它不能显示À â 这样的字符。
1 $value = htmlentities($this->value , ENT_QUOTES , 'UTF-8');
php 5.4之后的版本默认编码改为utf-8,这解决了许多问题,但清楚这一点仍然是推荐的如果你的应用是多语言的。