The 10 most common mistakes in PHP programming, PHP programming 10_PHP tutorial

WBOY
Release: 2016-07-13 10:18:26
Original
747 people have browsed it

10 most common mistakes in PHP programming, php programming 10

PHP is a very popular open source server-side scripting language used on most websites you see on the World Wide Web All are developed using php. This article will introduce you to the 10 most common problems in PHP development. I hope it can be helpful to your friends.

Error 1: Leaving dangling pointers after foreach loop

In the foreach loop, if we need to change the iterated elements or to improve efficiency, using references is a good way:

1 2 3 4 5 $arr = array(1, 2, 3, 4); foreach ($arr as &$value) { $value = $value * 2; } // $arr is now array(2, 4, 6, 8)

There is a question that many people will be confused about. After the loop ends, $value is not destroyed. $value is actually a reference to the last element in the array. If you don't know this in the subsequent use of $value, it will cause some inexplicable errors:) Take a look below. This code:

1 2 3 4 5 6 7 8 $array = [1, 2, 3]; echo implode(',', $array), "n";   foreach ($array as &$value) {}    // by reference echo implode(',', $array), "n";   foreach ($array as $value) {}     // by value (i.e., copy) echo implode(',', $array), "n";

The results of the above code are as follows:

1 2 3 1,2,3 1,2,3 1,2,2

Did you guess it right? Why is this result?

Let’s analyze it. After the first loop, $value is a reference to the last element in the array. The second cycle begins:

  • Step one: copy $arr[0] to $value (note that $value is a reference to $arr[2] at this time), then the array becomes [1,2,1]
  • Step 2: Copy $arr[1] to $value, then the array becomes [1,2,2]
  • Step 3: Copy $arr[2] to $value, then the array becomes [1,2,2]

In summary, the final result is 1,2,2

The best way to avoid this error is to use the unset function to destroy the variable immediately after the loop:

1 2 3 4 5 $arr = array(1, 2, 3, 4); foreach ($arr as &$value) {     $value = $value * 2; } unset($value);   // $value no longer references $arr[3]

Mistake 2: Misunderstanding of the behavior of isset() function

For the isset() function, false will be returned when the variable does not exist, and false will be returned when the variable value is null. This behavior can easily confuse people. . . Look at the code below:

1 2 3 4 $data = fetchRecordFromStorage($storage, $identifier); if (!isset($data['keyShouldBeSet']) {     // do something here if 'keyShouldBeSet' is not set }

The person who wrote this code may have intended that if $data['keyShouldBeSet'] is not set, the corresponding logic will be executed. But the problem is that even if $data['keyShouldBeSet'] has been set, but the set value is null, the corresponding logic will still be executed, which is not in line with the original intention of the code.

Here is another example:

1 2 3 4 5 6 7 8 9 if ($_POST['active']) {     $postData = extractSomething($_POST); }   // ...   if (!isset($postData)) {     echo 'post not active'; }

The above code assumes that $_POST['active'] is true, then $postData should be set, so isset($postData) will return true. Conversely, the above code assumes that the only way isset($postData) returns false is if $_POST['active'] also returns false.

Is this really the case? Of course not!

Even if $_POST['active'] returns true, $postData may be set to null, in which case isset($postData) will return false. This goes against the intent of the code.

If the purpose of the above code is only to detect whether $_POST['active'] is true, the following implementation would be better:

1 2 3 4 5 6 7 8 9 if ($_POST['active']) {     $postData = extractSomething($_POST); }   // ...   if ($_POST['active']) {     echo 'post not active'; }

To determine whether a variable is actually set (to distinguish between unset and set values ​​to null), the array_key_exists() function may be better. Refactor the first example above as follows:

1 2 3 4 $data = fetchRecordFromStorage($storage, $identifier); if (! array_key_exists('keyShouldBeSet', $data)) {     // do this if 'keyShouldBeSet' isn't set }

In addition, combined with the get_defined_vars() function, we can more reliably detect whether the variable is set in the current scope:

1 2 3 if (array_key_exists('varShouldBeSet', get_defined_vars())) {     // variable $varShouldBeSet exists in current scope }

Error 3: Confusing return values ​​and return references

Consider the following code:

1 2 3 4 5 6 7 8 9 10 11 12 13 class Config {     private $values = [];       public function getValues() {         return $this->values;     } }   $config = new Config();   $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

Running the above code will output the following content:

1 PHP Notice:  Undefined index: test in /path/to/my/script.php on line 21

What’s the problem? The problem is that the above code confuses return values ​​and return references. In PHP, unless you explicitly specify a return reference, PHP returns a value for an array, which is a copy of the array. Therefore, when the above code assigns a value to the returned array, it actually assigns a value to the copied array, not the original array.

1 2 3 4 5 6 7 // getValues() returns a COPY of the $values array, so this adds a 'test' element // to a COPY of the $values array, but not to the $values array itself. $config->getValues()['test'] = 'test';   // getValues() again returns ANOTHER COPY of the $values array, and THIS copy doesn't // contain a 'test' element (which is why we get the "undefined index" message). echo $config->getValues()['test'];

Here is a possible solution to output the copied array instead of the original array:

1 2 3 $vals = $config->getValues(); $vals['test'] = 'test'; echo $vals['test'];

If you just want to change the original array, that is, return the array reference, how should you deal with it? The way is to display the specified return reference:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Config {     private $values = [];       // return a REFERENCE to the actual $values array     public function &getValues() {         return $this->values;     } }   $config = new Config();   $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

After modification, the above code will output test as you expect.

Let’s look at another example that will make you even more confused:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Config {     private $values;       // using ArrayObject rather than array     public function __construct() {         $this->values = new ArrayObject();     }       public function getValues() {         return $this->values;     } }   $config = new Config();   $config->getValues()['test'] = 'test'; echo $config->getValues()['test'];

If you think that the “Undefined index” error will be output like above, then you are wrong. The code will output "test" normally. The reason is that PHP returns objects by reference by default, not by value.

In summary, when we use a function to return a value, we need to figure out whether it is a value return or a reference return. For objects in PHP, the default is to return by reference, and arrays and built-in basic types are returned by value by default. This should be distinguished from other languages ​​(many languages ​​pass arrays by reference).

Like other languages, such as java or C#, it is a better solution to use getters or setters to access or set class properties. Of course, PHP does not support it by default and you need to implement it yourself:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Config {     private $values = [];       public function setValue($key, $value) {         $this->values[$key] = $value;     }       public function getValue($key) {         return $this->values[$key];     } }   $config = new Config();   $config->setValue('testKey', 'testValue'); echo $config->getValue('testKey');    // echos 'testValue'

The above code allows the caller to access or set any value in the array without giving the array public access. How does it feel:)

Error 4: Executing sql query in a loop

It is not uncommon to find code similar to the following in PHP programming:

1 2 3 4 5 $models = [];   foreach ($inputValues as $inputValue) {     $models[] = $valueRepository->findByValue($inputValue); }

Of course there is nothing wrong with the above code. The problem is that during the iteration process, $valueRepository->findByValue() may execute the sql query every time:

1 $result = $connection->query("SELECT `x`,`y` FROM `values` WHERE `value`=" . $inputValue);

If it is iterated 10,000 times, then you have executed 10,000 SQL queries respectively. If such a script is called in a multi-threaded program, it is likely that your system will hang. . .

During the process of writing code, you should know when to execute the sql query, and try to retrieve all the data in one sql query.

There is a business scenario where you are likely to make the above mistakes. Suppose a form submits a series of values ​​(assumed to be IDs), and then in order to retrieve the data corresponding to all IDs, the code will traverse the IDs and execute sql queries for each ID respectively. The code is as follows:

1 2 3 4 5 $data = []; foreach ($ids as $id) {     $result = $connection->query("SELECT `x`, `y` FROM `values` WHERE `id` = " . $id);     $data[] = $result->fetch_row(); }

But the same purpose can be accomplished more efficiently in a sql, the code is as follows:

1 2 3 4 5 6 7 $data = []; if (count($ids)) {     $result = $connection->query("SELECT `x`, `y` FROM `values` WHERE `id` IN (" . implode(',', $ids));     while ($row = $result->fetch_row()) {         $data[] = $row;     } }

Mistake 5: Inefficient and illusionary memory usage

It is definitely more efficient to obtain multiple records in one SQL query than to obtain one record in each query. However, if you are using the MySQL extension in PHP, obtaining multiple records at one time is likely to cause memory overflow.

We can write code to experiment (test environment: 512MB RAM, MySQL, php-cli):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // connect to mysql $connection = new mysqli('localhost', 'username', 'password', 'database');   // create table of 400 columns $query = 'CREATE TABLE `test`(`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT'; for ($col = 0; $col < 400; $col++) { $query .= ", `col$col` CHAR(10) NOT NULL"; } $query .= ');'; $connection->query($query);   // write 2 million rows for ($row = 0; $row < 2000000; $row++) { $query = "INSERT INTO `test` VALUES ($row"; for ($col = 0; $col < 400; $col++) { $query .= ', ' . mt_rand(1000000000, 9999999999); } $query .= ')'; $connection->query($query); }

Now let’s look at resource consumption:

1 2 3 4 5 6 7 8 9 // connect to mysql $connection = new mysqli('localhost', 'username', 'password', 'database'); echo "Before: " . memory_get_peak_usage() . &amp;quot;n&amp;quot;;   $res = $connection->query('SELECT `x`,`y` FROM `test` LIMIT 1'); echo "Limit 1: " . memory_get_peak_usage() . &amp;quot;n&amp;quot;;   $res = $connection->query('SELECT `x`,`y` FROM `test` LIMIT 10000'); echo "Limit 10000: " . memory_get_peak_usage() . &amp;quot;n&amp;quot;;

The output results are as follows:

1 2 3 Before: 224704 Limit 1: 224704 Limit 10000: 224704

Judging from the memory usage, everything seems to be normal. To be more sure, try to get 100000 records at a time. As a result, the program gets the following output:

1 2 PHP Warning:  mysqli::query(): (HY000/2013):               Lost connection to MySQL server during query in /root/test.php on line 11

What’s going on?

The problem lies in the way PHP’s mysql module works. The mysql module is actually a proxy for libmysqlclient. While querying to obtain multiple records, these records will be stored directly in memory. Since this memory is not managed by the memory module of PHP, the value obtained by calling the memory_get_peak_usage() function is not the actual memory usage value, so the above problem occurs.

We can use mysqlnd instead of mysql. Mysqlnd is compiled into PHP's own extension, and its memory usage is controlled by the PHP memory management module. If we use mysqlnd to implement the above code, it will reflect the memory usage more realistically:

1 2 3 Before: 232048 Limit 1: 324952 Limit 10000: 32572912

To make matters worse, according to the official documentation of PHP, the memory used by the mysql extension to store query data is twice that of mysqlnd, so the original code uses about twice the memory shown above.

In order to avoid such problems, you can consider completing the query in several times to reduce the amount of data in a single query:

1 2 3 4 5 6 7 8 $totalNumberToFetch = 10000; $portionSize = 100;   for ($i = 0; $i <= ceil($totalNumberToFetch / $portionSize); $i++) { $limitFrom = $portionSize * $i; $res = $connection->query(                          "SELECT `x`,`y` FROM `test` LIMIT $limitFrom, $portionSize"); }

Based on the error 4 mentioned above, it can be seen that in the actual coding process, a balance must be achieved to not only meet the functional requirements, but also ensure performance.

Mistake 6: Ignoring Unicode/UTF-8 issues

In PHP programming, you will encounter some problems when dealing with non-ASCII characters. You must deal with them very carefully, otherwise you will get errors all over the place. Take a simple example, strlen($name), if $name contains non-ASCII characters, the results will be somewhat unexpected. Here are some suggestions to avoid such problems:

  • If you don’t know much about unicode and utf-8, then you should at least understand some of the basics. Recommended reading this article.
  • It is best to use mb_* functions to process strings and avoid using old string processing functions. Make sure PHP's "multibyte" extension is turned on.
  • It is best to use unicode encoding for databases and tables.
  • Know that the jason_code() function will convert non-ascii characters, but the serialize() function will not.
  • It is best to use UTF-8 format without BOM for PHP code source files.

Here is an article recommended to introduce this type of problem in more detail: UTF-8 Primer for PHP and MySQL

Mistake 7: Assuming $_POST always contains POST data

$_POST in PHP does not always contain the data submitted by form POST. Suppose we send a POST request to the server via the jQuery.ajax() method:

1 2 3 4 5 6 7 // js $.ajax({     url: 'http://my.site/some/path',     method: 'post',     data: JSON.stringify({a: 'a', b: 'b'}),     contentType: 'application/json' });

Pay attention to contentType: ‘application/json’ in the code. We are sending data in json data format. On the server side, we just output the $_POST array:

1 2 // php var_dump($_POST);

You will be surprised to find that the result is as follows:

1 array(0) { }

Why is this the result? Where did our json data {a: ‘a’, b: ‘b’} go?

The answer is that PHP only parses HTTP requests whose Content-Type is application/x-www-form-urlencoded or multipart/form-data. The reason for this is for historical reasons. When PHP first implemented $_POST, the above two types were the most popular. Therefore, although some types (such as application/json) are very popular now, automatic processing is still not implemented in PHP.

Since $_POST is a global variable, changing $_POST will be globally effective. Therefore, for requests whose Content-Type is application/json, we need to manually parse the json data and then modify the $_POST variable.

1 2 // php $_POST = json_decode(file_get_contents('php://input'), true);

At this point, if we output the $_POST variable, we will get the output we expect:

1 array(2) { ["a"]=> string(1) "a" ["b"]=> string(1) "b" }

Mistake 8: Thinking PHP supports character data types

Take a look at the code below and guess what will be output:

1 2 3 for ($c = 'a'; $c <= 'z'; $c++) { echo $c . &amp;quot;n&amp;quot;; }

If your answer is to output 'a' to 'z', then you will be surprised to find that your answer is wrong.

Yes, the above code does output 'a' to 'z', but in addition, it also outputs 'aa' to 'yz'. Let's analyze why this is the result.

There is no char data type in PHP, only string type. Understand this, then increment 'z', and the result is 'aa'. Regarding string size comparison, those who have studied C should know that 'aa' is smaller than 'z'. This also explains why there is the above output result.

If we want to output 'a' to 'z', the following implementation is a good way:

1 2 3 for ($i = ord('a'); $i <= ord('z'); $i++) { echo chr($i) . &amp;quot;n&amp;quot;; }

Or this is also OK:

1 2 3 4 5 $letters = range('a', 'z'); for ($i = 0; $i < count($letters); $i++) { echo $letters[$i] . &amp;quot;n&amp;quot;; }

Mistake 9: Ignoring coding standards

Although ignoring coding standards will not lead to errors or bugs, it is still important to follow certain coding standards.

Without unified coding standards, your project will have many problems. The most obvious thing is that your project code is inconsistent. Even worse, your code will be harder to debug, extend, and maintain. This also means that your team's efficiency will be reduced, including doing a lot of meaningless work.

For PHP developers, it is relatively lucky. Because there is a PHP Coding Standard Recommendation (PSR), which consists of the following 5 parts:

  • PSR-0: Automatic loading standard
  • PSR-1: Basic Coding Standard
  • PSR-2: Coding Style Guide
  • PSR-3: Logging interface standard
  • PSR-4: Autoloading

PSR was originally created and followed by several large groups in the PHP community. Zend, Drupal, Symfony, Joomla and other platforms have contributed to and adhere to this standard. Even PEAR wanted to become a standard in the early years, but now it has joined the PSR camp.

In some cases, it doesn’t matter what coding standard you use, as long as you use a coding style and stick with it. But following the PSR standard is a good idea, unless you have some special reason to make one yourself. Now more and more projects are beginning to use PSR, and most PHP developers are also using PSR. Therefore, using PSR will make new members of your team familiar with the project faster and will be more comfortable when writing code.

Error 10: Wrong use of empty() function

Some PHP developers like to use the empty() function to make Boolean judgments on variables or expressions, but it can be confusing in some cases.

First, let’s take a look at the array Array and array object ArrayObject in PHP. There seems to be no difference, they are all the same. Is this really the case?

1 2 3 4 5 6 // PHP 5.0 or later: $array = []; var_dump(empty($array)); // outputs bool(true) $array = new ArrayObject(); var_dump(empty($array)); // outputs bool(false) // why don't these both produce the same output?

To make things a little more complicated, take a look at the following code:

1 2 3 4 5 // Prior to PHP 5.0: $array = []; var_dump(empty($array)); // outputs bool(false) $array = new ArrayObject(); var_dump(empty($array)); // outputs bool(false)

Unfortunately, the above method is very popular. For example, in Zend Framework 2, ZendDbTableGateway does this when calling the current() method on the TableGateway::select() result set to return a data set. Developers can easily fall into this trap.

To avoid these problems, the last resort to check if an array is empty is to use the count() function:

1 2 3 4 5 // Note that this work in ALL versions of PHP (both pre and post 5.0): $array = []; var_dump(count($array)); // outputs int(0) $array = new ArrayObject(); var_dump(count($array)); // outputs int(0)

By the way, because PHP considers the value 0 to be a Boolean value false, the count() function can be directly used in the conditional judgment of the if conditional statement to determine whether the array is empty. In addition, the count() function has a complexity of O(1) for arrays, so using the count() function is a wise choice.

Let’s look at another example where using the empty() function is dangerous. It is also dangerous when using the empty() function in combination with the magic method __get(). Let's define two classes, each with a test attribute.

First we define the Regular class, which has a test attribute:

1 2 3 4 class Regular { public $test = 'value'; }

Then we define the Magic class and use the __get() magic method to access its test attribute:

1 2 3 4 5 6 7 8 9 10 11 class Magic { private $values = ['test' => 'value'];       public function __get($key)     {         if (isset($this->values[$key])) {             return $this->values[$key];         }     } }

Okay. Let’s now see what happens when accessing the test attribute of each class:

1 2 3 4 $regular = new Regular(); var_dump($regular->test);    // outputs string(4) "value" $magic = new Magic(); var_dump($magic->test);      // outputs string(4) "value"

So far, everything is normal and it doesn’t make us feel confused.

But what happens if you use the empty() function on the test attribute?

1 2 var_dump(empty($regular->test));    // outputs bool(false) var_dump(empty($magic->test));      // outputs bool(true)

Is the result surprising?

Unfortunately, if a class uses the magic __get() function to access the value of a class attribute, there is no easy way to check whether the attribute value is empty or does not exist. Outside the class scope, you can only check if a null value is returned, but this does not necessarily mean that the corresponding key is not set, because the key value can be set to null .

In contrast, if we access a non-existent property of the Regular class, we will get a Notice message similar to the following:

1 2 3 4 Notice: Undefined property: Regular::$nonExistantTest in /path/to/test.php on line 10   Call Stack:     0.0012     234704   1. {main}() /path/to/test.php:0

Therefore, for the empty() function, we must use it carefully, otherwise the results will be unexpected and even potentially misleading you.

 By: Eddy Translated from: 10 Most Common PHP Mistakes

A PHP programming question: Assume that the ten letters of abcdefghij represent the ten numbers 0123456789 respectively

function zh($x){
$num=strlen($x);
$str='abcdefghij';
for($i=0;$i&amp;amp;lt ;$num;$i++){
$arr[]=substr($x,$i,1);
$zhstr.=$str[$arr[$i]];
}
return $zhstr;
}

$str=zh('1563'); //Set initial value
print($str);
?>

php programming problem, please help

This is a problem with table locking. You lock the table directly when reading, and the next user will have to wait temporarily. But it’s generally not handled this way. This will make the website experience very poor.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/884176.htmlTechArticle10 most common mistakes in PHP programming, php programming 10 PHP is a very popular open source server-side script Language, most of the websites you see on the World Wide Web are developed using PHP. This article...
Related labels:
php
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!