簡體   English   中英

PHP多個if / elseif和錯誤消息/處理最佳實踐

[英]PHP multiple if / elseif and error messaging / handling best practices

這是一個我經常遇到的問題,我從來沒有找到/想出最佳實踐情況。 例外可能是要走的路,但是我正在使用的應用程序沒有使用它們,所以我試圖堅持使用當前使用的方法。

如果需要檢查3,4,5或更多不同的條件並且設置了錯誤消息或處理繼續,則在語句,返回,消息等中布置if的最佳方法是什么。 最好的做法是在代碼開頭實際進行所有錯誤檢查嗎?

這是一個真實世界類型條件的例子。

function process($objectId,$userId,$newData)
{
    $error = '';
    if(($object = $this->getObject($objectId)) && $object->userOwnsObject($userId))
    {
        if($this->isValid($newData))
        {
            if($object->isWriteable())
            {
                if($object->write($newData))
                {
                    // No error. Success!
                }
                else
                {
                    $error = 'Unable to write object';
                }
            }
            else
            {
                $error = 'Object not writeable';
            }
        }
        else
        {
            $error = 'Data invalid';
        }
    }
    else
    {
        $error = 'Object invalid';
    }
    return $error;
}

要么

function process($objectId,$userId,$newData)
{
    $error = '';
    if((!$object = $this->getObject($objectId)) && !$object->userOwnsObject($userId))
    {
        $error = 'Object invalid';
    }
    elseif(!$this->isValid($newData))
    {
        $error = 'Data invalid';
    }
    elseif(!$object->isWriteable())
    {
         $error = 'Object not writeable';
    }
    elseif(!$object->write($newData))
    {
        $error = 'Unable to write to object';
    }
    else
    {
        // Success!
    }
    return $error;
}

我很清楚,在這種情況下,選項2是要走的路。 它更清晰。 現在,我們可以讓它更復雜一點:

function process($objectId,$userId,$newData)
{
    $error = '';
    if(($object = $this->getObject($objectId)) && $object->userOwnsObject($userId))
    {
        $this->setValidationRules();
        $parent = $object->getParentObject();
        $parent->prepareForChildUpdate();

        if($this->isValid($newData,$parent))
        {
            $newData = $this->preProcessData($newData);

            if($object->isWriteable())
            {
                // doServerIntensiveProcess() has no return value and must be done between these two steps
                $this->doServerIntensiveProcess();

                if($object->write($newData))
                {
                    // No error. Success!
                    $parent->childUpdated();
                }
                else
                {
                    $error = 'Unable to write object';
                }
            }
            else
            {
                $error = 'Object not writeable';
            }
        }
        else
        {
            $error = 'Data invalid';
        }
    }
    else
    {
        $error = 'Object invalid';
    }
    return $error;
}

或者這有一些問題

function process($objectId,$userId,$newData)
{
    $error = '';
    if((!$object = $this->getObject($objectId)) && !$object->userOwnsObject($userId))
    {
        $error = 'Object invalid';
    }
    // Is it wrong to hate multi-line conditionals?
    elseif(!$this->setValidationRules() || (!$parent = $object->getParentObject()) ||
        !$parent->prepareForChildUpdate() || !$this->isValid($newData,$parent))
    {
        $error = 'Data invalid';
    }
    elseif((!$newData = $this->preProcessData($newData)) || !$object->isWriteable())
    {
         $error = 'Object not writeable';
    }
    // Where does doServerIntensiveProcess() with no return value go??
    elseif(!$object->write($newData))
    {
        $error = 'Unable to write to object';
    }
    else
    {
        // Success!
         $parent->childUpdated();
    }
    return $error;
}

我只是不確定處理這個嵌套的最佳方法 - 如果那么那么做 - 然后 - 如果這樣那么做 - 那種功能。 感謝您提供的任何見解!

我傾向於保持代碼清潔是這樣的:

function process($objectId,$userId,$newData)
{
    $object = $this->getObject($objectId);

    if($object === false)
    {
        return "message";
    }

    if($object->userOwnsObject($userId) === false)
    {
        return "message";
    }

    if($this->setValidationRules() === false)
    {
        return "unable to set validation rules";
    }

    if(false !== ($parent = $object->getParentObject()))
    {
        return "unable to get parent object";
    }

    /*... etc ...*/

    //if your here the all the checks above passed.
}

通過這樣做你也可以節省你的資源直接返回到位,代碼看起來更干凈,不需要2個巢

但是如果你從頭開始構建函數我不明白為什么你不能在你的新代碼中使用異常,它不會干擾當前的應用程序,並使生活更簡單

function process($objectId,$userId,$newData)
{    
    if(false !== ($parent = $object->getParentObject()))
    {
          throw Exception("unable to get parent object");
    }

    /*... etc ...*/
}

try
{
    $this->process(....);
}
catch(Exception $e)
{
    show_error_page('invalid.php',$e);
}

或者另一種方法是使用名為InternalError的靜態方法創建一個錯誤處理類,如此

abstract class Error
{
    public static InternalError(Exception $Ex)
    {
        Logger::LogException($Ex);
        //Then flush all buffers and show internal error,
    }
}

所以不是上面的show_error_page,你可以這樣做:

try
{
    $this->process(....);
}
catch(Exception $e)
{
    Error::InternalError($e); //this provides user with an interface to report the error that has just been logged.
}

通過這種方式,您的所有Exception被記錄下來,並且可以在您的管理系統中查看,這意味着您可以更快地跟蹤錯誤,而不是依靠成員明顯地看到錯誤,而是通過電子郵件表單向他們道歉,要求他們描述錯誤試圖這樣做,錯誤ID將附加到表單,因此您可以跟蹤用戶的錯誤。

這是IMO錯誤處理的最佳形式。

那這個呢?

function process($objectId,$userId,$newData)
{
    if((!$object = $this->getObject($objectId)) && !$object->userOwnsObject($userId))
        return 'Object invalid';
    elseif(!$this->isValid($newData))
        return 'Data invalid';
    elseif(!$object->isWriteable())
        return 'Object not writeable';
    elseif(!$object->write($newData))
        return 'Unable to write to object';

    // Success!
}

對於更復雜的例子::

function process($objectId,$userId,$newData)
{
    if(!($object = $this->getObject($objectId)) || !$object->userOwnsObject($userId))
        return 'Object invalid';

    $this->setValidationRules();
    $parent = $object->getParentObject();
    $parent->prepareForChildUpdate();

    if(!$this->isValid($newData,$parent))
        return 'Data Invalid';

    $newData = $this->preProcessData($newData);

    if(!$object->isWriteable())
        return 'Object not writable';

    // doServerIntensiveProcess() has no return value and must be done between these two steps
    $this->doServerIntensiveProcess();

    if(!$object->write($newData))
        return 'Unable to write object';

    // No error. Success!
    $parent->childUpdated();
    return '';
}

我會完全省略

if($object->isWriteable())
{
    if($object->write($newData))
    {
        // ..
    }
}

並且在調用object-write() (不帶返回值)時拋出異常。 其他例子也一樣

if ($something->isValid($data)) {
    $op->doSomething($data); // throws XyException on error
}

如果你真的想用這樣的結構,你也可以使用動開關語句來

switch (true) {
    case !$something->isValid($data):
        $errors = "error";
        break;
    // and so an
}

但我真的推薦例外。

我認為編寫多行條件本身並不是錯誤的,但是你可以通過將條件放入變量並在if-statment中使用它來使其更具可讀性。 我認為elseif構造更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM