三元运算符里面计算PHP

时间:2016-07-12 01:07:24

标签: php

我正在尝试使用对象中包含的值的总和来设置数组。但是,当在对象中未设置其中一个属性(此示例中为“shares”)时,操作应该继续而不会引发以下错误:

“[ErrorException] Undefined property:stdClass :: $ shares”

我正在尝试使用三元运算符来实现此目的,如下所示:

$array = [strtotime('today midnight') =>
           $ExternalPost->reactions->summary->total_count ?: 0 +
           $ExternalPost->comments->summary->total_count ?: 0 +
           ($ExternalPost->shares->count ? $ExternalPost->shares->count : 0)
         ];

看起来运算符正在评估所有内容,包括其他两个前面的对象/值。如何将评估值限制为最后一个“$ ExternalPost-> shares-> count”?

4 个答案:

答案 0 :(得分:2)

我建议重写你的逻辑,这样它就不会同时使用多个三元运算符。 PHP comparison operators documentation说:

  

注意:

     

建议您避免"堆叠"三元表达式。在单个语句中使用多个三元运算符时,PHP的行为是不明显的:

     

示例#4非明显的三元行为

<?php
// on first glance, the following appears to output 'true'
echo (true?'true':false?'t':'f');

// however, the actual output of the above is 't'
// this is because ternary expressions are evaluated from left to right

// the following is a more obvious version of the same code as above
echo ((true ? 'true' : false) ? 't' : 'f');

// here, you can see that the first expression is evaluated to 'true', which
// in turn evaluates to (bool)true, thus returning the true branch of the
// second ternary expression.
?>

这是因为PHP的三元运算符是左关联的而不是右关联的,就像在大多数其他语言中一样。

答案 1 :(得分:1)

如果未定义$ExternalPost->shares,则没有理由在没有该错误的情况下继续操作。如果您正在检查$ExternalPost->shares->count

,则需要定义此选项

否则,您可以将逻辑更改为:

((isset($ExternalPost->shares) && $ExternalPost->shares->count) ? $ExternalPost->shares->count : 0)

答案 2 :(得分:0)

如果您尝试访问不存在的对象属性或数组键,PHP将抛出错误,即使您只是这样做以检查它是否存在。相反,您应该使用property_exists()(对于对象),或array_key_exists()(对于数组)或isset()(对于任何事物)。使用其中一种方法可以检查变量/属性/键是否存在而不会抛出错误,如果它没有。

您的示例可以重写为:

...
(isset($ExternalPost->shares->count) ? $ExternalPost->shares->count : 0)

答案 3 :(得分:0)

您的原始代码相当于

if ($ExternalPost->reactions->summary->total_count) {
    $a = $ExternalPost->reactions->summary->total_count;
} else {
    if ($ExternalPost->comments->summary->total_count) {
      $a = 0 + $ExternalPost->comments->summary->total_count;
    } elseif($ExternalPost->shares->count) {
      $a = 0 + $ExternalPost->shares->count
    } else {
      $a = 0;
    }
}

示例http://ideone.com/c9bY5o

三元条件应包含括号和属性验证,以区分现有值和检索值。

(isset($ExternalPost->reactions->summary->total_count) ? $ExternalPost->reactions->summary->total_count : 0) +
(isset($ExternalPost->comments->summary->total_count) ? $ExternalPost->comments->summary->total_count : 0) +
(isset($ExternalPost->shares->count) ? $ExternalPost->shares->count : 0);

否则使用详细格式,这更容易阅读。

if (isset($ExternalPost->reactions->summary->total_count)) {
    $a = $ExternalPost->reactions->summary->total_count;
} else {
    $a = 0;
}
if (isset($ExternalPost->comments->summary->total_count)) {
    $a += $ExternalPost->comments->summary->total_count;
} else {
    $a += 0;
}
if (isset($ExternalPost->shares->count)) {
    $a += $ExternalPost->shares->count;
} else {
    $a += 0;
}

示例http://ideone.com/GKkpZw

请注意,该对象已移除reactionsshares个属性。

至于建议,我建议您将方法分配给对象并以此方式获取总计。因此,您只需要在一个位置维护计算,并且能够在其他脚本中重复使用它。

这样,如果你想对数据做一些更复杂的事情,需要在别处显示它,或者你决定稍后更改或添加对象或计算,它会更容易。例如,只有当帖子有份额或添加向上和向下投票时,总计反应和评论。

Rough Lazy Getter OOP示例 - 它可以重构为在设置值时计算总数,接受一组值等等。

class ExternalPost
{
    private $reactions;

    private $comments;

    private $shares;

    public function __construct(Reactions $reactions = null, Comments $comments = null, Shares $shares = null) 
    {
        $this->reactions = $reactions;
        $this->comments = $comments;
        $this->shares = $shares;
    }

    public function getReactions()
    {
        if (null === $this->reactions) {
            $this->reactions = new Reactions;
        }
        return $this->reactions;
    }

    public function getComments()
    {
        if (null === $this->comments) {
            $this->comments = new Comments;
        }
        return $this->comments;
    }

    public function getShares()
    {
        if (null === $this->shares) {
            $this->shares = new Shares;
        }
        return $this->shares;
    }

    public function getTotal() 
    {
        return $this->getReactions()->getTotal() + 
            $this->getComments()->getTotal() + 
            $this->getShares()->getCount();
    }
}
class Summary 
{
    private $total_count = 0;

    public function getTotalCount() 
    {
        return $this->total_count;
    }

    public function setTotalCount($total)
    {
        $this->total_count = $total;

        return $this;
    }
}
abstract class Summation 
{
    protected $summary;

    public function __construct(Summary $summary = null) 
    {
        $this->summary = $summary;
    }

    public function getSummary()
    {
        if (null === $this->summary) {
            $this->summary = new Summary;
        }

        return $this->summary;
    }

    public function getTotal() 
    {
        return $this->getSummary()->getTotalCount();
    }

    public function setTotal($total)
    {
        $this->getSummary()->setTotalCount($total);

        return $this;
    }
}

class Reactions extends Summation{}

class Comments extends Summation{}
class Shares 
{
    private $count = 0;

    public function getCount() 
    {
        return $this->count;
    }

    public function setCount($count)
    {
        $this->count = $count;

        return $this;
    }
}

所以现在脚本中的代码看起来像

$reactions = new Reactions;
$reactions->setTotal(1);
$comments = null; 
/*
 $comments = new Comments;
 $comments->setTotal(2);
 //alternative to using getComments below
*/

$ExternalPost = new ExternalPost($reactions, $comments);
/* $ExternalPost->getReactions()->setTotal(1);
   //alternative to defining $reactions above */
$ExternalPost->getComments()->getSummary()->setTotalCount(2);
$ExternalPost->getShares()->setCount(3);

$array = [strtotime('today midnight') => $ExternalPost->getTotal()];

示例http://ideone.com/oqSYNd

您还可以应用__set__get魔术方法来保留您当前的代码格式,但我们强烈建议不要这样做,因为它会让您的代码更容易理解。