PHP - 这是否正确使用了类中的错误处理异常?

时间:2012-04-16 05:50:38

标签: php class exception error-handling design-principles

我在这个主题上搜索了很多,并且得到了很多好的(但不同的)结果。一些结果并不是很相关,最后似乎确实是一个偏好的问题,但如果我遵循良好的设计原则,我很感兴趣

如果问题过于模糊,请随意将其删除,但是您可以推荐我发布的地址吗?

此外,这只是的一个例子。这里有很多东西,我通常会采用不同的方式,但为了简单起见,我这样做了。

代码很长,但你应该能够复制&将其直接粘贴到一个新的PHP文件中并在您的环境中运行;无需设置。

具体问题

  • 这是使用异常并在调用方处理它们的正确方法吗?
  • 我是否应该为此使用例外?
  • 我的骨架自定义例外是否正确?

代码

您可以在单独的窗口here中查看副本。我会把它贴在这里。保存并在您的环境中运行它,它应该按原样运行而不做任何修改:

注意:提前编码

<?php

    error_reporting ( E_ALL | E_STRICT );




    class MemberLoginException extends Exception
    {

        public function __construct ( $message = null, $code = 0, Exception $previous = null )
        {
            parent::__construct ( $message, $code, $previous );
        }

    }




    class AccountsInsertException extends Exception
    {

        public function __construct ( $message = null, $code = 0, Exception $previous = null )
        {
            parent::__construct ( $message, $code, $previous );
        }

    }




    class AccountsManager
    {

        protected $_accounts = array ();
        protected $_lcUsernames = array ();     # all usernames in lowercase for checking if username is taken



        public function __construct ( array $accounts = null )
        {
            $this->setAllAccounts ( $accounts );
        }



        public function __destruct ()
        {
            unset ( $this->_accounts, $this->_lcUsernames );
        }



        public function __toString ()
        {
            $return = '';

            if ( count ( $this->_accounts ) > 0 ) :

                $return = '<table>';
                $return .= '<tr><th>Username</th><th>Password</th></tr>';

                foreach ( $this->_accounts as $account ) :

                    $return .= 
                    '<tr>
                        <td>'. htmlentities ( $account['username'], ENT_QUOTES, 'UTF-8' ) . '</td>
                        <td>'. htmlentities ( $account['password'], ENT_QUOTES, 'UTF-8' ) . '</td>
                    </tr>';

                endforeach;

                $return .= '</table>';

                return $return;
            endif;
        }



        public function Clear ()
        {
            $this->_accounts = array ();
            $this->_lcUsernames = array ();
        }



        public function Authenticate ( Member $member )
        {
            $username = strtolower ( $member->getUsername () );

            if ( count ( $this->_accounts ) ) :

                foreach ( $this->_accounts as $account ) :

                    if ( strtolower ( $account['username'] ) == $username )
                        return ( bool ) ( $account['password'] == $member->getPassword () );

                endforeach;

            else :
                return false;
            endif;
        }



        public function getAllAccounts ()
        {
            return $this->_accounts;
        }



        public function setAllAccounts ( array $newValue = null )
        {
            if ( is_null ( $newValue ) )
                $this->_accounts = array ();
            else
                $this->_accounts = $newValue;
                $this->_lcUsernames = array ();

                foreach ( $this->_accounts as $account )
                    $this->_lcUsernames[] = strtolower ( $account['username'] );

            return $this;
        }



        public function hasAccount ( $username )
        {
            return in_array ( strtolower ( $username ), $this->_lcUsernames, false );
        }



        public function AddAccount ( $username, $password )
        {

            /*
            Faster to be redundant by storing a lowercase copy of the username for comparison

            if ( array_key_exists ( strtolower ( $username ), array_change_key_case ( $this->_accounts ) ) )
                throw new AccountsInsertException ( 'Unable to create account; account already exists.' );
            */

            if ( $this->hasAccount ( $username ) )
                throw new AccountsInsertException ( 'Unable to create account; account already exists.' );

            $this->_accounts[] = array (
                'username' => $username,
                'password' => $password,
            );

            $this->_lcUsernames[] = strtolower ( $username );
            return $this;
        }



        public function RemoveAccount ( $username )
        {
            if ( $this->hasAccount ( $username ) ) :
                unset ( $this->_accounts[$username] );
                unset ( $this->_lcUsernames [ strtolower ( $username ) ] );
            endif;

            return $this;
        }



        public function __Debug ()
        {
            echo "\r<pre>\r";
            print_r ( $this->_accounts );
            echo "\r</pre>\r\r\r<pre>\r";
            print_r ( $this->_lcUsernames );
            echo "\r</pre>\r\r";
        }

    }




    class Member
    {

        protected $_username = '';
        protected $_password = '';



        public function __construct ( $username, $password )
        {
            $this->setUsername ( $username );
            $this->setPassword ( $password );
        }



        public function getUsername ()
        {
            return $this->_username;
        }



        public function setUsername ( $newValue )
        {
            $this->_username = ( string ) $newValue;
            return $this;
        }



        public function getPassword ()
        {
            return $this->_password;
        }



        public function setPassword ( $newValue )
        {
            $this->_password = ( string ) $newValue;
            return $this;
        }

    }


    # create a new accounts manager which stores all accounts and handles authentication
    # the Member class would be responsible for setting session variables, etc. Manager just checks user/pass.
    $manager = new AccountsManager ();

?><!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />

        <style>

            *
            {
                font-family: "Segoe UI", "Trebuchet MS", Tahoma, Arial, Helvetica, sans-serif;
            }

            body
            {
                margin: 4em 6em;
                line-height: 1.6em;
                font-size: smaller;
            }

            header
            {
                border-bottom: 2px solid #efefef;
                margin-bottom: 3em;
                padding-bottom: 1em;
            }

            h1, h2, h3, h4, h5, h6
            {
                font-weight: normal;
                letter-spacing: 1px;
                color: royalblue;
            }

            h5, h6
            {
                font-weight: bold;
            }

            header h1 sub, header h1 sup
            {
                font-size: small;
                color: #FF4400;
                letter-spacing: 2px;
            }

            section
            {
                border-bottom: 1px dotted #ccc;
                padding-bottom: 2em;
                margin-bottom: 3em;
            }

            table
            {
                border: 1px solid #eee;
                padding: 1em;
                border-right-width: 2px;
                border-bottom-width: 2px;
            }

            th
            {
                text-align: left;
                font-variant: small-caps;
                border-bottom: 1px dotted #ccc;
                padding-bottom: .75em;
                margin-bottom: .75em;
                letter-spacing: 1px;
                color: #FF4400;
            }

            td:hover
            {
                background-color: skyblue;
            }

            td
            {
                margin: 0;
                display: table-cell;
                padding: .5em;
            }

            pre
            {
                font-family: "Droid Sans Mono", Consolas, "Courier New", Courier, monospaced;
                border: 1px solid #E4E4E4;
                padding: 1em;
                line-height: 1em;
            }

            .error
            {
                color: red;
                border: 1px dotted #ccc;
            }

            .success
            {
                color: forestgreen;
                border: 1px dotted #e0e0e0;
            }

            .error, .success
            {
                padding: .75em;
                background-color: #FFFFCC;
                border: 1px solid #E4E4E4;
            }

        </style>

        <title>Sample Login System - Test Exceptions</title>
    </head>

    <body>

        <header>
            <h1>Simple Login System <sup>demonstrating exceptions&hellip;</sup></h1>
        </header>



        <section>
            <h2>No database required</h2>

            <p>To avoid time setting up your environment, this test simply uses a class that stores an array of accounts.
            Obviously, this isn't persistent (at this time) and it doesn't actually save anything anywhere except in the
            array during the script's lifetime. Upon the next request, the previous accounts will be erased.</p>
        </section>



        <section>
            <h2>Creating accounts...</h2>

            <?php

                $createList =
                    array (

                        array (
                            'username' => 'Daniel Elkins',
                            'password' => 'delkins[not-pass-for-anything]',
                        ),

                        array (
                            'username' => 'Jennifer Lynn',
                            'password' => 'lilJenn',
                        ),

                        array (
                            'username'=> 'Charlie Dog',
                            'password'=> 'grrrrr',
                        ),

                    );

                if ( $manager->setAllAccounts ( $createList ) instanceof AccountsManager ) : ?>

                    <p><strong>Accounts were created successfully!</strong> They should be listed in
                    a table below.</p>

                <?php

                else :

                ?>

                    <p class="error">There was an error creating your accounts...</p>

                <?php

                endif;

            ?>

        </section>


        <section>
            <h2>List of accounts</h2>

            <?php echo $manager; ?>

        </section>


        <section>
            <h2>Trying to create one that already exists...</h2>

            <?php

            try
            {
                $manager->AddAccount ( 'Daniel Elkins', 'delkins[not-pass-for-anything]'); ?>

                <p class="success">Account created successfully!</p>

                <?php

            }
            catch ( AccountsInsertException $exception )
            {
                ?>

                <p class="error"><?= $exception->getMessage (); ?></p>

                <?php

            }

            ?>

        </section>


        <section>
            <h2>Showing accounts again</h2>

            <?php echo $manager; ?>

        </section>


        <section>
            <h2>Valid login test</h2>

            <p>Logging in user `Daniel Elkins`&hellip;</p>

            <?php

            if ( $manager->Authenticate ( new Member ( 'Daniel Elkins', 'delkins[not-pass-for-anything]' ) ) ) : ?>

                <p class="success">Authentication successful!</p>

                <?php

            else :

            ?>

                <p class="error">Unable to login; invalid username or password!</p>

                <?php

            endif;

            ?>

        </section>


        <section>
            <h2><strong>Invalid</strong> login test</h2>

            <p>Logging in user `Doesnt_Exist`&hellip;</p>

            <?php

            if ( $manager->Authenticate ( new Member ( 'Doesnt_Exist', '1234' ) ) ) : ?>

                <p class="success">Authentication successful!</p>

                <?php

            else :

            ?>

                <p class="error">Unable to login; invalid username or password!</p>

                <?php

            endif;

            ?>

        </section>


        <section>
            <h2>Debug information</h2>

            <?php $manager->__Debug (); ?>

        </section>

    </body>

</html>

1 个答案:

答案 0 :(得分:1)

  

这是使用异常并在其上处理它们的正确方法吗?   来电方?

对我来说似乎是一种合理的方法。你抛出特定于类的异常,因此很容易捕获或传播它们,只有特定的异常而不是必须捕获所有内容并过滤。

  

我是否应该为此使用例外?

如果您认为账户存在的特殊情况,是的。

  

我的骨架自定义异常是否正确?

是的,虽然您可以考虑在其中添加元数据,例如在AccountInsertException中创建的帐户的名称。它可能没有必要,但是如果你发现自己处于有用的状态,那只需要考虑。

否则代码在某些地方有点乱,但我假设它部分是因为这个例子。