PHP编程中最常见的错误,你犯了几个?

 2024-02-18 05:02:37  阅读 0

错误1:循环后在循环中留下悬空指针。 如果我们需要改变迭代的元素或者提高效率,使用引用是一个好方法: $arr = array(1,2,3,4); ($arr as&$value){ $value = $value *2; } // $arr 现在是 array(2, 4, 6, 8) 这里有一个问题很多人都会感到困惑。

错误1:循环后留下悬空指针

在循环中,如果我们需要改变迭代的元素或者提高效率,使用引用是一个好方法:

$arr=数组(1,2,3,4);

($arras&$value){

$值=$值*2;

// $arr 现在是 array(2, 4, 6, 8)

这里有一个问题,很多人都会感到困惑。 循环结束后,$value不会被销毁。 $value 实际上是对数组中最后一个元素的引用。 如果在后续使用$value的时候不知道这一点,会导致一些莫名其妙的错误:)看看下面。 这段代码:

$数组=[1,2,3];

(',',$array),"\n";

($&$value){}// 通过

(',',$array),"\n";

($$value){}//按值(即复制)

(',',$array),"\n";

上述代码运行结果如下:

1,2,3

1,2,3

1,2,2

你猜对了吗? 为什么会是这样的结果呢?

我们来分析一下。 在第一个循环之后,$value 是对数组中最后一个元素的引用。 第二个循环开始:

第一步:将$arr[0]复制到$value(注意$value是对$arr[2]的引用),则数组变为[1,2,1]

第二步:复制$arr[1]到$value,则数组变为[1,2,2]

第三步:复制$arr[2]到$value,则数组变为[1,2,2]

综上,最终结果是1,2,2

避免此错误的最佳方法是在循环后立即使用 unset 函数销毁变量:

$arr=数组(1,2,3,4);

($arras&$value){

$值=$值*2;

unset($value);// $value 没有 $arr[3]

错误 2:对 isset() 函数行为的误解

对于isset()函数,当变量不存在时返回false,当变量值为null时返回false。 这种行为很容易迷惑人们。 。 。 看下面的代码:

$数据=ge($,$);

if(!isset($data['']){

// 如果未设置 '' 则在此执行

写这段代码的人可能本意是,如果$data['']没有设置,就会执行相应的逻辑。 但问题是,即使已经设置了$data[''],但设置的值为null,仍然会执行相应的逻辑,这不符合代码的初衷。

这是另一个例子:

如果($_POST['']){

$=($_POST);

// ...

如果(!isset($)){

echo '不发布';

上面的代码假设$_POST['']为true,那么$应该被设置,所以isset($)将返回true。 相反,上面的代码假设 isset($) 返回 false 的唯一方法是 $_POST[''] 也返回 false。

事实真的如此吗? 当然不是!

即使 $_POST[''] 返回 true,$ 也可能被设置为 null,在这种情况下 isset($) 将返回 false。 这违背了代码的意图。

php传值和传引用区别_php传值与传引用的区别_php引用传递

如果上面代码的目的只是检测$_POST['']是否为true,那么下面的实现会更好:

如果($_POST['']){

$=($_POST);

// ...

如果($_POST['']){

echo '不发布';

要确定一个变量是否真正被设置(以区分未设置和设置值为 null),() 函数可能更好。 将上面的第一个示例重构如下:

$数据=ge($,$);

if(!('',$data)){

// 如果未设置 '' 则执行此操作

另外,结合()函数,我们可以更可靠地检测变量是否在当前作用域内设置:

如果(('',())){

// $ 范围内

错误3:混淆返回值和返回引用

考虑以下代码:

$=[];

(){

$这个->;

$=();

$->()['测试']='测试';

echo$->()['测试'];

运行上面的代码会输出如下内容:

::/path/to/my/.php

有什么问题? 问题在于上面的代码混淆了返回值和返回引用。 在 PHP 中,除非显式指定返回引用,否则 PHP 将返回数组的值,该值是数组的副本。 因此,当上面的代码给返回的数组赋值时,它实际上是给复制的数组赋值,而不是给原始数组赋值。

// () $ 数组的副本,因此这会添加一个“测试”

// 复制到 $ 数组,但不复制到 $ 数组。

$->()['测试']='测试';

// () 再次复制 $ 数组,而这个复制没有

// 一个“测试”(这就是我们得到“索引”的原因)。

echo$->()['测试'];

这是输出复制的数组而不是原始数组的可能解决方案:

$vals=$->();

$vals['测试']='测试';

echo$vals['测试'];

如果只是想改变原来的数组,即返回数组引用,应该如何处理呢? 方式是显示指定的返回引用:

$=[];

// a 到 $ 数组

&(){

$这个->;

$=();

$->()['测试']='测试';

echo$->()['测试'];

修改后,上面的代码将按照您的预期输出 test

让我们看一个会让你更加困惑的例子:

$;

// 使用比数组

(){

$这个->=();

(){

$这个->;

$=();

$->()['测试']='测试';

echo$->()['测试'];

如果您认为“index”错误会像上面那样输出,那您就错了。 代码将正常输出“test”。 原因是 PHP 默认通过引用返回对象,而不是通过值。

综上所述,当我们使用函数返回值时,我们需要弄清楚是值返回还是引用返回。 对于PHP中的对象,默认是按引用返回,数组和内置基本类型默认是按值返回。 这要和其他语言区分开来(很多语言都是通过引用传递数组)。

与其他语言(例如 Java 或 C#)一样,它是使用或访问或设置类属性的更好解决方案。 当然PHP默认是不支持的,需要自己实现:

$=[];

($键,$值){

$this->[$key]=$value;

($键){

$this->[$key];

$=();

$->('','');

echo$->('');// 回显 ''

上面的代码允许调用者访问或设置数组中的任何值,而无需授予数组访问权限。 你感觉如何:)

错误4:循环执行sql查询

在 PHP 编程中,类似以下的代码并不罕见:

$=[];

($$){

$[]=$->($);

当然上面的代码没有任何问题。 问题是$->()在迭代过程中可能每次都会执行sql查询:

$=$->query(" `x`,`y` FROM `` WHERE `value`=".$);

如果迭代10000次,那么就分别执行了10000条sql查询。 如果在多线程程序中调用这样的脚本,很可能你的系统会挂起。 。 。

在编写代码的过程中,您应该知道何时执行SQL查询,并尝试在一个SQL查询中检索所有数据。

有一个业务场景你很可能会犯上述错误。 假设一个表单提交了一系列值(假设为ID),那么为了检索所有ID对应的数据,代码会遍历ID,分别对每个ID执行sql查询。 代码如下:

$数据=[];

($idsas$id){

$=$->query(" `x`, `y` FROM `` WHERE `id` = ".$id);

$数据[]=$->();

但在 SQL 中可以更有效地实现相同的目的。 代码如下:

$数据=[];

如果(计数($ids)){

$=$->query(" `x`, `y` FROM `` WHERE `id` IN (".(',',$ids));

而($行=$->()){

$数据[]=$行;

错误5:内存使用效率低下且错误

在一个 SQL 查询中获取多条记录肯定比在每个查询中获取一条记录更高效。 然而,如果您在PHP中使用MySQL扩展,一次获取多条记录很可能会导致内存溢出。

我们可以编写代码进行实验(测试环境:512MB RAM、MySQL、php-cli):

// 到mysql

$=('','','','');

// 400 的表

$query=' TABLE `test`(`id` INT NOT NULL KEY ';

为($col=0;$col

$query.=", `col$col` CHAR(10) NOT NULL";

$query.=');';

$->查询($查询);

// 写入2行

为($行=0;$行

$query=" INTO `test` ($row";

为($col=0;$col

$query.=', '.(,);

$查询.=')';

$->查询($查询);

现在我们看一下资源消耗:

// 到mysql

$=('','','','');

echo": ".e()."\n";

$res=$->query(' `x`,`y` FROM `test` LIMIT 1');

echo"限制 1: ".e()."\n";

$res=$->query(' `x`,`y` FROM `test` LIMIT 10000');

echo"限制 10000: ".e()."\n";

输出如下:

从内存使用情况来看,一切似乎都很正常。 为了更加确定,请尝试一次获取一项记录。 结果,程序得到以下输出:

:::查询():(HY000/2013):

/root/test.php 上

这是怎么回事?

问题在于 PHP 的 mysql 模块的工作方式。 mysql模块实际上是一个代理。 当查询获取多条记录时,这些记录会直接存储在内存中。 由于这块内存不是由PHP的内存模块管理的,所以我们通过调用e()函数得到的值并不是实际使用的内存值,所以就会出现上面的问题。

我们可以用它代替mysql,编译成PHP自己的扩展,它的内存使用情况由PHP内存管理模块控制。 如果我们用上面的代码来实现的话,会更真实的反映内存的使用情况:

更糟糕的是,根据 PHP 的官方文档,MySQL 扩展使用两倍的内存来存储查询数据,因此原始代码使用的内存大约是上图所示的两倍。

为了避免此类问题,可以考虑分几次完成查询,以减少单次查询的数据量:

$=10000;

$=100;

为($i=0;$(

" `x`,`y` FROM `test` LIMIT $, $");

联系上面提到的错误4,我们可以看出,在实际编码过程中,必须取得一个平衡,既要满足功能需求,又要保证性能。

标签: php test php数组函数

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码