简体   繁体   中英

How to handle business logic errors effectively?

Let's suppose we have some objects hierarchy built via composition. Is there any pattern to register business logic errors within inner objects and pass them to the upper objects ?

I am just tired of all these addErrors , getErrors on each level and I feel that I do something incorrectly.

I know about exceptions, but I have no mind how to use them in such case. Business logic error is technically not a critical situation, which should result in interruption of the program execution. Actually interruption is not supposed at all, because we need to register the error and just move on.

Thanks in advance to share your wisdom and knowledge )

Small snippet to illustrate the problem:

class ErrorContainer {
    private $errors = array();
    function addError($error) { if (!is_array($error)) { $this->errors[] = $error;} else { $this->errors = array_merge($this->errors, $error); } }
    function getErrors() { return $this->errors[]; }
    function hasErrors() { return !empty($this->errors); }
}

class Processor extends ErrorContainer {
    function process($account_id, $orders) {
        $account = new Account();
        if (!$account->loadById($account_id)) { $this->addErrors($account->getErrors);}

        foreach ($orders as $order_id) {
            $order = new Order();
            if (!$order->loadById($order_id)) { $this->addErrors($order->getErrors);}
        }
    }

    return $this->hasErrors();
}

class Account extends ErrorContainer {
    function loadById($account_id) {
        $account = select_from_database($account_id);
        if (!$account) { $this->addError("Account is missing"); }
        if (!$account['active']) { $this->addError("Account is inactive"); }
        // and so on, some checks may add errors in a cycle

        return $this->hasErrors();
    }
}

class Order extends ErrorContainer {} // very similar to Account, but has its own checks

//Usage:

$errors = array();
$items = load_items_from_xml($xml);
foreach ($items as $item) {
    $processor = new Processor();
    if (!$processor->process($item['account_id'], $item['orders'])) {
        $errors = array_merge($errors, $processor->getErrors());
    }
}

Exceptions aren't used only in critical situations, but in your case it's not such a bad idea to use the error system you have now. You might consider using constants instead of text for errors, and define all possible error constants in each class.

class Account extends ErrorContainer {
    const ERR_ACC_MISSING = 0;
    const ERR_ACC_INACTIVE = 1;
    function loadById($account_id) {
        $account = select_from_database($account_id);
        if (!$account) { $this->addError(ERR_ACC_MISSING); }
        if (!$account['active']) { $this->addError(ERR_ACC_INACTIVE); }
        // and so on, some checks may add errors in a cycle

        return $this->hasErrors();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM