从PHP中的空值创建默认对象?


362

仅在将我的PHP环境升级到PHP 5.4及更高版本后,我才看到此错误。错误指向以下代码行:

错误:

从空值创建默认对象

码:

$res->success = false;

我首先需要声明我的$res对象吗?


11
您如何/在哪里发起的$res
2012年

1
@NAVEED 那里
7heo.tk 2016年

Answers:


627

您的新环境可能已针对<= 5.3.x的PHP版本启用了E_STRICT警告,或者仅针对至少>> 5.4的PHP版本设置了警告。当触发了错误的或者尚未初始化:error_reportingerror_reportingE_WARNING$resNULL

$res = NULL;
$res->success = false; // Warning: Creating default object from empty value

如果$res已经初始化为某个值但不是对象,则PHP将报告不同的错误消息:

$res = 33;
$res->success = false; // Warning: Attempt to assign property of non-object

为了符合E_STRICTPHP 5.4之前的标准或E_WARNINGPHP> = 5.4中的常规错误级别,假设您尝试创建一个通用对象并分配该属性success,则需要在全局名称空间中声明$res为的对象stdClass

$res = new \stdClass();
$res->success = false;

38
您应该检查对象是否已经存在:if (!isset($res)) $res = new stdClass();。否则,此代码不能等效地替代“旧PHP”隐式对象的创建。
TMS

6
@Tomas是否需要再次执行此操作?国防部上次清理注释线程,因为它增加了很少的价值。没有“旧的PHP”隐式对象创建。它始终是一个错误,并始终发出警告,只是它已在5.4中从E_STRICT更改为E_WARNING,因此有些人从未遇到过它而没有注意E_STRICT。
Michael Berkowski

4
@PeterAlfvin 在那个特定的运行中没有定义!但是在不同的运行中,可能在代码中的完全相同的位置,已经定义了对象!这是人们常做的想法上的错误,这就是我试图强调这一点的原因。
TMS

2
迈克尔,隐式对象的创建一直存在,甚至在5.4中仍然存在。顺便说一句,在PHP <5.3中,它既不是E_STRICT也不是E_WARNING。顺便说一句,mod已恢复了评论,并被告知要淡化,这就是为什么我重新发布了它。
TMS

3
@tomas哦,好吧,我我明白你的意思。您/迈克尔无法就此达成协议似乎很奇怪。顺便说一句,这种交流使我意识到斜体字<bold <allcaps在“强度”方面,并且虽然allcaps = shoulding和italics = politeEmphasis,但粗体字在接受性值得怀疑的中间立场。:-)
彼得·阿尔夫文

57

此消息E_STRICT适用于PHP <= 5.3。从PHP 5.4开始,它很不幸地更改为E_WARNING。由于E_WARNING消息很有用,因此您不想完全禁用它们。

要摆脱此警告,您必须使用以下代码:

if (!isset($res)) 
    $res = new stdClass();

$res->success = false;

这是完全等效的替换。它可以确保PHP默默地做同样的事情-不幸的是现在发出警告-隐式对象创建。除非绝对确定不存在,否则应始终检查对象是否已存在。Michael提供的代码通常不好,因为在某些情况下,根据情况,有时可能已在代码的同一位置定义了该对象。


2
@carlosvini,这会给你的Undefined variable: res
Pacerier,2015年

1
@Pacerier你是对的,最好的办法是:$ res = isset($ res)?$ res:新的stdClass(); -这是六个月前我没有启用E_NOTICE的原因,因为它太冗长了。
carlosvini 2015年

13

只是,

    $res = (object)array("success"=>false); // $res->success = bool(false);

或者,您可以使用以下方法实例化类:

    $res = (object)array(); // object(stdClass) -> recommended

    $res = (object)[];      // object(stdClass) -> works too

    $res = new \stdClass(); // object(stdClass) -> old method

并用以下值填充值:

    $res->success = !!0;     // bool(false)

    $res->success = false;   // bool(false)

    $res->success = (bool)0; // bool(false)

更多信息:https : //www.php.net/manual/zh/language.types.object.php#language.types.object.casting


为什么新的stdClass()被视为“旧”方法?其他人更好吗?
亚伦

它只是来自旧的php版本
pirs,

在我的情况下$this->route->uri = new stdClass();对我不起作用,我仍然有警告。注意:$this->route存在。
Meloman

也许这与新版本的php不兼容?您使用的是哪个版本?
PIRS

6

如果您在行首添加“ @”字符,则PHP不会在该行显示任何警告/通知。例如:

$unknownVar[$someStringVariable]->totalcall = 10; // shows a warning message that contains: Creating default object from empty value

为防止此行出现此警告,必须在该行的开头放置“ @”字符,如下所示:

@$unknownVar[$someStringVariable]->totalcall += 10; // no problem. created a stdClass object that name is $unknownVar[$someStringVariable] and created a properti that name is totalcall, and it's default value is 0.
$unknownVar[$someStringVariable]->totalcall += 10; // you don't need to @ character anymore.
echo $unknownVar[$someStringVariable]->totalcall; // 20

我在开发时使用了这个技巧。我不喜欢禁用所有警告消息,因为如果您不能正确处理警告,那么将来它们将成为一个大错误。


1
@确实通过抑制警告来防止警告,只要您具有可管理的代码,它就可以正常显示。但是,如果您的代码增长到更大的规模而又遇到问题,您将以某种方式后悔使用它。您会发现自己在寻找所有要取消隐藏的警告时使用“ @”,因为它暂时达到了目的,以为您实际上已解决了该问题,而实际上它一直在与您交谈,而您不会听。
文森特·爱德华·加德里亚·比努阿,2015年

我已经知道了。这是简短而快速的答案。为此有很多解决方案。
kodmanyagha

2
太棒了!但是,请允许我表示不同意,隐藏错误并不能真正解决问题(正如Ramy Nasr所说的那样)。
文森特·爱德华·加德里亚·比努阿,2015年

此变通办法是对我在php 7.2上唯一的解决方法。
Meloman

3

如果您有数组并向其中添加对象,请尝试此操作。

$product_details = array();

foreach ($products_in_store as $key => $objects) {
  $product_details[$key] = new stdClass(); //the magic
  $product_details[$key]->product_id = $objects->id; 
   //see new object member created on the fly without warning.
}

这将发送对象数组以供以后使用〜!


谢谢!!!!这就是帮助完成工作的原因。我需要逐步告诉PHP每个元素是什么。感谢您提醒我不要编写懒惰的笑声。
yanike

2

尝试这个:

ini_set('error_reporting', E_STRICT);

1
谢谢。当您使用诸如nusoap之类的第三方库且不希望/无法更改源时,此库已满。在这种情况下,可以在需要其他源文件之前将error_reporting更改为E_STRICT级别。
mtoloo

尽管我只是将此添加到nusoap的顶部以解决我的问题。
badweasel 2014年

11
??此处的代码禁用除E_STRICT错误以外的所有错误报告,包括禁止显示致命错误消息。解决这个特定警告不是一个合理的建议,而且,您几乎从未想过这样做。为什么有5个人对此表示支持,我却一无所知。
Mark Amery 2014年

1
这太糟糕了!ini_set('error_reporting', -1);在调试时使用,但不要像以往一样使用以上内容。
卡扎伊16/12/30

好的,所以您可以通过隐藏此问题来解决问题?不知道你的代码将继续按照预期...
PIRS

1

我有类似的问题,这似乎可以解决问题。您只需要将$ res对象初始化为class即可。假设这里的类名是test。

class test
{
   //You can keep the class empty or declare your success variable here
}
$res = new test();
$res->success = false;

1

这是我在PHP 7中遇到的警告,对此的简单解决方法是在使用变量之前对其进行初始化

$myObj=new \stdClass();

初始化之后,便可以将其用于对象

 $myObj->mesg ="Welcome back - ".$c_user;

0

引起此问题的原因是您正在分配一个未启动的对象实例。例如:

您的情况:

$user->email = 'exy@gmail.com';

解:

$user = new User;
$user->email = 'exy@gmail.com';

您是否不假设存在“用户”类?它可能不会,现在会产生另一个错误?
克里斯托弗·托马斯

1
实际上,我没有创建User对象的实例,因此出现错误。但是在创建实例之后。它起作用了..这是OOPs概念的一个普遍问题:)
Bastin Robin

6
好吧,实际上,真正的问题是您的示例假设要定义用户类,这不是面向对象的通用问题,这是一个关键要求;)
Christopher Thomas,

1
我宁愿放置一个通用的“ stdClass”来代替暗含“ User”的前提。
TechNyquist

0

获取此错误的一种简单方法是在下面键入(a),这意味着键入(b)

(一个) $this->my->variable

(b) $this->my_variable

琐碎,但很容易被忽略,如果您不想要它,很难发现它。


这与原始问题有什么关系?_->
Nico Haase

0

您可能需要检查变量是否已声明并具有正确的类型。

if (!isset($res) || !is_object($res)) {
    $res = new \stdClass();
    // With php7 you also can create an object in several ways.
    // Object that implements some interface.
    $res = new class implements MyInterface {};
    // Object that extends some object.
    $res = new class extends MyClass {};
} 

$res->success = true;

参见PHP匿名类


0

尝试将变量添加到API返回的对象时遇到类似的问题。我正在使用foreach循环遍历数据。

foreach ( $results as $data ) {
    $data->direction = 0;
}

这在Laravel中引发了“从空值创建默认对象”异常。

我用很小的改动就解决了。

foreach ( $results as &$data ) {
    $data->direction = 0;
}

通过简单地使$ data为参考。

我希望这可以帮助某人,这使我烦恼!


0
  1. 首先认为您应该创建对象$ res = new \ stdClass();

  2. 然后为对象分配键和值thay $ res-> success = false;


(我不明白thay。)如果要在某些内容后换行,请在要中断的行之前在行的可见内容后附加两个空格。
灰胡子

-1

不,您不..当您将成功值添加到对象时,它将创建它。如果您不指定默认值,则默认类将被继承。


4
尽管它将返回Strict标准消息...这是首先手动创建对象的简单好习惯,并且尽管PHP相对可以容忍劣质的编码实践,但您不应忽略正确地做事。
Mark Ba​​ker

4
理解,我只是以简单的“是”或“是”回答问题,而不是定义或捍卫最佳实践:)
Silvertiger 2012年


-12

我将以下内容放在有问题的PHP文件的顶部,并且不再显示错误:

error_reporting(E_ERROR | E_PARSE);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.