Improvement of PHP code quality 36 1. do not use relative paths
We often see:
require_once('../../lib/some_class.php');
This method has many disadvantages:
It first looks for the specified php inclusion path and then finds the current directory.
Therefore, excessive paths are checked.
If the script is included by another script, its basic directory is changed to the directory where another script is located.
Another problem is that when a scheduled task runs the script, its parent directory may not be a working directory.
Therefore, the best choice is to use the absolute path:
define('ROOT' , '/var/www/project/');require_once(ROOT . '../../lib/some_class.php');//rest of the code
We have defined an absolute path, and the value has been written to death. we can also improve it. the path/var/www/project may also change, so should we change it every time? No, we can use the _ FILE _ constant, for example:
//suppose your script is /var/www/project/index.php//Then __FILE__ will always have that full path.define('ROOT' , pathinfo(__FILE__, PATHINFO_DIRNAME));require_once(ROOT . '../../lib/some_class.php');//rest of the code
Now, no matter which Directory you move to, such as moving to an Internet server, the code can run correctly without any changes.
2. do not directly use require, include, include_once, required_once
You can introduce multiple files in the script header, such as class libraries, tool files, and helper functions. for example:
require_once('lib/Database.php');require_once('lib/Mail.php');require_once('helpers/utitlity_functions.php');
This usage is quite primitive. it should be more flexible. a helper function should be compiled to include files. for example:
function load_class($class_name){ //path to the class file $path = ROOT . '/lib/' . $class_name . '.php'); require_once( $path );}load_class('Database');load_class('Mail');
Is there anything different? The code is more readable.
You can extend the function as needed, for example:
function load_class($class_name){ //path to the class file $path = ROOT . '/lib/' . $class_name . '.php'); if(file_exists($path)) { require_once( $path ); }}
You can also do more:
Search for multiple directories for the same file
It is easy to change the directory where class files are stored, without having to modify them one by one throughout the code.
You can use similar functions to load files, such as html content.
3. retain the debugging code for the application
In the development environment, we print database query statements and store problematic variable values. Once the problem is solved, we comment or delete them. However, it is better to retain the debugging code.
In the development environment, you can:
define('ENVIRONMENT' , 'development');if(! $db->query( $query ){ if(ENVIRONMENT == 'development') { echo "$query failed"; } else { echo "Database error. Please contact administrator"; }}
On the server, you can:
define('ENVIRONMENT' , 'production');if(! $db->query( $query ){ if(ENVIRONMENT == 'development') { echo "$query failed"; } else { echo "Database error. Please contact administrator"; }}
4. execute commands using cross-platform functions
System, exec, passthru, and shell_exec functions can be used to execute system commands. every behavior has a slight difference. the problem is that some functions may be selectively disabled in the shared host. most new users tend to check which function is available at first, but use it again.
A better solution is to block functions into a cross-platform function.
/**Method to execute a command in the terminalUses :1. system2. passthru3. exec4. shell_exec*/function terminal($command){//systemif(function_exists('system')){ob_start();system($command , $return_var);$output = ob_get_contents();ob_end_clean();}//passthruelse if(function_exists('passthru')){ob_start();passthru($command , $return_var);$output = ob_get_contents();ob_end_clean();}//execelse if(function_exists('exec')){exec($command , $output , $return_var);$output = implode("n" , $output);}//shell_execelse if(function_exists('shell_exec')){$output = shell_exec($command) ;}else{$output = 'Command execution not possible on this system';$return_var = 1;}return array('output' => $output , 'status' => $return_var);}terminal('ls');
The above function will run shell commands, as long as there is a system function available, which maintains code consistency.
5. flexible function writing
function add_to_cart($item_id , $qty){ $_SESSION['cart']['item_id'] = $qty;}add_to_cart( 'IPHONE3' , 2 );
Use the above function to add a single project. when adding an item list, do you want to create another function? No, as long as you pay attention to different types of parameters, it will be more flexible. for example:
function add_to_cart($item_id , $qty){ if(!is_array($item_id)) { $_SESSION['cart']['item_id'] = $qty; } else { foreach($item_id as $i_id => $qty) { $_SESSION['cart']['i_id'] = $qty; } }}add_to_cart( 'IPHONE3' , 2 );add_to_cart( array('IPHONE3' => 2 , 'IPAD' => 5) );
Now, the same function can process different types of input parameters. you can refer to the above example to reconstruct your multiple code to make it smarter.
6. intentionally ignore php to close the tag
I 'd like to know why this is not mentioned in so many blog articles on php suggestions.
This will save you a lot of time. for example, a super_class.php file
//super extra character after the closing tag
Index. php
require_once('super_class.php');//echo an image or pdf , or set the cookies or session data
In this way, you will get a Headers already send error. why? Because "super extra character" has been output, you have to start debugging now. this will take a lot of time to find the location of super extra. Therefore, develop the habit of omitting the close character:
This will be better.
7. collect all input in a certain place and output it to the browser at a timeThis is called the output buffer. assume that you have output content in different functions:
function print_header(){ echo "Site Log and Login links";}function print_footer(){ echo "Site was made by me";}print_header();for($i = 0 ; $i ';}print_footer();
Instead, collect the output in a specific place. you can store the output in the local variables of the function, or use ob_start and ob_end_clean:
function print_header(){ $o = "Site Log and Login links"; return $o;}function print_footer(){ $o = "Site was made by me"; return $o;}echo print_header();for($i = 0 ; $i ';}echo print_footer();
Why do I need an output buffer?> You can change the output before sending it to the browser. for example, the str_replaces function may be preg_replaces or add some monitoring/debugging html content.> the output to the browser is also very bad for php processing. you should have seen an error message in the sidebar or in the middle of some sites. do you know why? Because the processing and output are mixed.
8. send the correct mime type header information, if the output is not html content.Output some xml.
$xml = '';$xml = "0";//Send xml dataecho $xml;
Work well, but some improvements are needed.
$xml = '';$xml = "0";//Send xml dataheader("content-type: text/xml");echo $xml;
Note the header line. this row tells the browser to send xml content. so the browser can handle it correctly. many javascript libraries also rely on header information. similar to javascript, css, jpg image, png image: JavaScript
header("content-type: application/x-javascript");echo "var a = 10";
CSS
header("content-type: text/css");echo "#p id { background:#000; }";
9. set correct character encoding for mysql connectionsI have encountered unicode/UTF-8 encoding in the mysql table, and phpadmin can be correctly displayed, but garbled characters may occur when you get the content and output it on the page. the problem lies in the character encoding of mysql connections.
//Attempt to connect to database$c = mysqli_connect($this->host , $this->username, $this->password);//Check connection validityif (!$c) {die ("Could not connect to the database host: ". mysqli_connect_error());}//Set the character set of the connectionif(!mysqli_set_charset ( $c , 'UTF8' )){die('mysqli_set_charset() failed');}
Once you connect to the database, it is best to set the connected characterset. if your application must support multiple languages, this is required.
10. use htmlentities to set correct encoding optionsPhp5.4, character encoding is the default ISO-8859-1, can not directly output such as â.
$value = htmlentities($this->value , ENT_QUOTES , CHARSET);
After php5.4, the default encoding is UTF-8, which will solve a lot of problems. but if your application is multilingual, still pay attention to coding problems ,.
11. do not use gzip to compress the output in the application for apache to processHave you considered using ob_gzhandler? Don't do that. it's meaningless. php should only be used to write applications. you shouldn't worry about data transmission optimization for servers and browsers. use the mod_gzip/mod_deflate module of apache to compress content.
12. use json_encode to output dynamic javascript contentPhp is often used to output dynamic javascript content:
$images = array( 'myself.png' , 'friends.png' , 'colleagues.png');$js_code = '';foreach($images as $image){$js_code .= "'$image' ,";}$js_code = 'var images = [' . $js_code . ']; ';echo $js_code;//Output is var images = ['myself.png' ,'friends.png' ,'colleagues.png' ,];
To be smarter, use json_encode:
$images = array( 'myself.png' , 'friends.png' , 'colleagues.png');$js_code = 'var images = ' . json_encode($images);echo $js_code;//Output is : var images = ["myself.png","friends.png","colleagues.png"]
Elegant?
13. check the directory write permission before writing a file.Make sure that the directory is writable before writing or saving the file. if not, output the error message. this will save you a lot of debugging time. in linux, permissions must be handled. improper directory permissions may cause many problems, and files may not be readable. make sure that your application is smart enough to output some important information.
$contents = "All the content";$file_path = "/var/www/project/content.txt";file_put_contents($file_path , $contents);
This is basically correct. but there are some indirect problems. file_put_contents may fail for several reasons:> the parent directory does not exist> the directory exists, but cannot be written> is the file written and locked? Therefore, it is better to make a clear check before writing the file.
$contents = "All the content";$dir = '/var/www/project';$file_path = $dir . "/content.txt";if(is_writable($dir)){ file_put_contents($file_path , $contents);}else{ die("Directory $dir is not writable, or does not exist. Please check");}
After doing so, you will get a clear information about where the file is written and why it fails.
14. change the file permissions created by the application.In linux, permission issues may waste a lot of time. from now on, whenever you create some files, make sure to use chmod to set the correct permissions. otherwise, the file may be first created by the "php" user, but when you log on to work with another user, the system will refuse to access or open the file, and you have to struggle to obtain the root permission, change file permissions, etc.
// Read and write for owner, read for everybody elsechmod("/somedir/somefile", 0644);// Everything for owner, read and execute for otherschmod("/somedir/somefile", 0755);
15. do not rely on the value of the submit button to check the form submission behaviorif($_POST['submit'] == 'Save'){ //Save the things}
Most of the above situations are correct, except that the application is multilingual. 'save' may represent other meanings. how do you differentiate them? therefore, do not rely on the value of the submit button.
if( $_SERVER['REQUEST_METHOD'] == 'POST' and isset($_POST['submit']) ){ //Save the things}
Now you are freed from the value of the submit button.
16. define static variables for variables with the same value in the function.//Delay for some timefunction delay(){ $sync_delay = get_option('sync_delay'); echo "Delaying for $sync_delay seconds..."; sleep($sync_delay); echo "Done ";}
Replace with static variables:
//Delay for some timefunction delay(){ static $sync_delay = null; if($sync_delay == null) {$sync_delay = get_option('sync_delay'); } echo "Delaying for $sync_delay seconds..."; sleep($sync_delay); echo "Done ";}
17. do not directly use the $ _ SESSION variableSome simple examples:
$_SESSION['username'] = $username;$username = $_SESSION['username'];
This may cause some problems. if multiple applications are running in the same domain name, the session variable may conflict. two different applications may use the same session key. for example, a front-end portal and a background management system use the same domain name. from now on, use the key related to the application and a packaging function:
define('APP_ID' , 'abc_corp_ecommerce');//Function to get a session variablefunction session_get($key){ $k = APP_ID . '.' . $key; if(isset($_SESSION[$k])) { return $_SESSION[$k]; } return false;}//Function set the session variablefunction session_set($key , $value){ $k = APP_ID . '.' . $key; $_SESSION[$k] = $value; return true;}
18. encapsulate tool functions into classesAssume that you have defined many tool functions in a file:
function utility_a(){ //This function does a utility thing like string processing}function utility_b(){ //This function does nother utility thing like database processing}function utility_c(){ //This function is ...}
The usage of these functions is scattered throughout the application. you may want to encapsulate them into a class:
class Utility{ public static function utility_a() { } public static function utility_b() { } public static function utility_c() { }}//and call them as $a = Utility::utility_a();$b = Utility::utility_b();
The obvious advantage is that if a function with the same name is built in php, conflicts can be avoided. another idea is that you can maintain multiple versions for the same class in the same application without causing a conflict. this is the basic benefit of encapsulation, without it.
19. Bunch of silly tips> Replace print with echo> replace preg_replace with str_replace, unless you absolutely need to> do not use short tag> replace double quotation marks with single quotes in a simple string> use exit after head redirection> do not call a function in a loop> isset is faster than strlen >>> for example, format the code >>> Do not delete the loop or if-else parentheses. do not write the code like this:
if($a == true) $a_count++;
This is absolutely WASTE. written:
if($a == true){ $a_count++;}
Do not try to omit some syntax to shorten the code. Instead, make your logic brief.> use a text editor with highlighted syntax. the highlighted syntax can reduce errors.
20. use array_map to quickly process arraysFor example, if you want to trim all elements in the array, new users may:
foreach($arr as $c => $v){$arr[$c] = trim($v);}
However, using array_map is simpler:
$arr = array_map('trim' , $arr);
This will apply to call trim for every element of the $ arr array. another similar function is array_walk. please refer to the document for more tips.
21. use php filter to verify dataYou must have used regular expressions to verify emails and IP addresses. yes, this applies to everyone. now, we want to make different attempts, called filter. php's filter extension provides a simple way to verify and check input.
22. Force type check$amount = intval( $_GET['amount'] );$rate = (int) $_GET['rate'];
This is a good habit.
23. if necessary, use profiler such as xdebugIf you use php to develop large applications, php takes a lot of computations, and the speed will be a very important indicator. use profile to help optimize code. xdebug and webgrid can be used.
24. handle large arrays with cautionYou must be careful when handling large arrays and strings. a common Error is that Memory overflow occurs due to an array copy and Fatal Error of Memory size is thrown:
$db_records_in_array_format; //This is a big array holding 1000 rows from a table each having 20 columns , every row is atleast 100 bytes , so total 1000 * 20 * 100 = 2MB$cc = $db_records_in_array_format; //2MB moresome_function($cc); //Another 2MB ?
This is often done when you import or export csv files. do not think that the above code will often cause script crashes due to memory restrictions. small variables are fine, but must be avoided when processing large arrays. make sure that it is passed by reference or stored in class variables:
$a = get_large_array();pass_to_function(&$a);
After doing so, pass the variable reference (instead of copying the array) to the function. view the document.
class A{ function first() { $this->a = get_large_array(); $this->pass_to_function(); } function pass_to_function() { //process $this->a }}
Unset them as soon as possible to release the memory and reduce the script burden.
25. use a single database to connect to the databaseMake sure that all scripts use a single database connection from the beginning. open the connection correctly at the beginning, use it until the end, and close it. do not open the connection in the function as follows:
function add_to_cart(){ $db = new Database(); $db->query("INSERT INTO cart .....");}function empty_cart(){ $db = new Database(); $db->query("DELETE FROM cart .....");}
Using multiple connections is too bad. they will slow down the application because it takes time and memory to create the connection. The Singleton mode is used in specific cases, such as database connection.
26. avoid writing SQL directly and abstract itToo many of the following statements have been written:
$query = "INSERT INTO users(name , email , address , phone) VALUES('$name' , '$email' , '$address' , '$phone')";$db->query($query); //call to mysqli_query()
This is not a strong solution. it has some disadvantages:> manually escaping values each time> verifying that the query is correct> the query error takes a long time to identify (unless it is checked by if-else each time)> it is difficult to maintain complex queries. Therefore, function encapsulation is used:
function insert_record($table_name , $data){ foreach($data as $key => $value) {//mysqli_real_escape_string $data[$key] = $db->mres($value); } $fields = implode(',' , array_keys($data)); $values = "'" . implode("','" , array_values($data)) . "'"; //Final query $query = "INSERT INTO {$table}($fields) VALUES($values)"; return $db->query($query);}$data = array('name' => $name , 'email' => $email , 'address' => $address , 'phone' => $phone);insert_record('users' , $data);
Have you seen it? This will make it easier to read and expand. the record_data function carefully handles the escape. the biggest advantage is that the data is preprocessed into an array, and any syntax errors will be captured. this function should be defined in a database class. you can call it like $ db-> insert_record. read this article to see how to make it easier for you to process the database. similarly, you can write the update, select, and delete methods. try it.
27. cache the content generated by the database to a static file.If all contents are obtained from the database, they should be cached. once generated, they are saved in temporary files. the next time you request this page, you can directly retrieve it from the cache without querying the database. benefits:> saving php processing page time and faster execution> less database queries mean less mysql connection overhead
28. Save the session in the databaseThe file-based session policy has many restrictions. the file-based session cannot be extended to the cluster because the session is stored on a single server. however, the database can be accessed by multiple servers to solve the problem. saving session data in the database has more advantages:> handling repeated username logon problems. you cannot log on to the same username in two locations at the same time.> more prepared online user status query.
29. avoid using global variables> Use defines/constants> use functions to obtain values> use classes and access through $ this
30. use the base tag in the headHave you heard of it? See the following:
Base labels are very useful. suppose your application is divided into several sub-directories, which must contain the same navigation menu.
Www.domain.com/store/home.php
Www.domain.com/store/products/ipad.php
On the homepage, you can write:
HomeIpad
But on your ipad. php, you have to write:
HomeIpad
Because the directories are different, there are so many different versions of navigation menus to be maintained, which is very bad.
Therefore, use the base tag.
HomeIpad
Now, this code is stored in the directory files of the application and the behavior is consistent.
31. never set error_reporting to 0Disable the non-phase error report. E_FATAL error is very important.
ini_set('display_errors', 1);error_reporting(~E_WARNING & ~E_NOTICE & ~E_STRICT);
32. pay attention to the platform architectureInteger length is different in the 32-bit and 64-bit architectures. Therefore, some functions such as strtotime may behave differently.
In a 64-bit machine, you will see the following output.
$ php -aInteractive shellphp > echo strtotime("0000-00-00 00:00:00");-62170005200php > echo strtotime('1000-01-30');-30607739600php > echo strtotime('2100-01-30');4104930600
But in 32-bit machines, they will be bool (false ).
33. do not rely too much on set_time_limitIf you want to limit the minimum time, you can use the following script:
set_time_limit(30);//Rest of the code
Sit back and relax? Note that any external execution, such as system calls, socket operations, and database operations, is not under the control of set_time_limits.
Therefore, even if the database spends a lot of time querying, the script will not stop running, depending on the situation.
34. Use Extension LibrarySome examples:
> MPDF-generate pdf documents through html
> PHPExcel-read and write excel
> PhpMailer-it is easy to process and send emails containing nearby emails.
> PChart-generate reports using php
Use open-source libraries to complete complex tasks, such as generating pdf, ms-excel files, and reports.
35. use the MVC frameworkIt is time to use MVC frameworks like codeigniter. MVC frameworks do not force you to write object-oriented code. they only separate php code from html.
> Clearly differentiate php and html code. it is helpful for team collaboration. designers and programmers can work at the same time.
> Object-oriented functions make it easier for you to maintain
> The built-in functions have completed a lot of work and you do not need to write them again.
> Development of large applications is required.
> Many suggestions, tips, and hack have been implemented by the framework.
36. always look at phpbenchPhpbench provides benchmark test results for some basic php operations. it shows how small syntax changes lead to huge differences.
Check the comments of the php Site, ask IRC if you have any questions, read the open source code frequently, and use Linux for development.