Взять на абстракции БД и PHP / MySQL для


Это немного больше кода, но я хотел показать полный класс. Я выделяю те моменты, которые я хотел бы после ввода источника.

Я отключил комментарии так как они не на английском и перевел важные из них.

Класс навеян PearDb (слишком старый) и Zend_DB (в суматоху / незаконченное на тот момент) и используется в приложении номере. Я знаю, что это не идея написать свой собственный обработчик базы данных (я бы пойти так далеко, чтобы сказать довольно бессмысленной :) ) но учитывая, что позволяет взглянуть на код:

Код

<?php

class DbStatement {

    private $oStatement;
    private $aFieldnames = array();
    private $aResultRow = array();
    private $aResultSet = array();
    private $bMetadata = true;
    private $bPreparedFetch = false;
    private $iNumRows = false;
    private $sQuery;
    private $aArgs;
    private $fQuerytime;

    /**
     * @throws DbException
     * @param mysqli $oDb Datenbankverbindung
     * @param string $sQuery
     */
    public function __construct(mysqli $oDb, $sQuery) {
        $this->oStatement = $oDb->prepare($sQuery);
        $this->sQuery = $sQuery;
        if($this->oStatement === false) {
            switch($oDb->errno) {
                case 1054:
                    throw new DbNoSuchFieldException($oDb->error, $oDb->errno);
                case 1146:
                    throw new DbNoSuchTableException($oDb->error, $oDb->errno);
                default:
                    throw new DbException(
                        "Prepared Statement could not be created: ".
                        $oDb->error." (".$oDb->errno."). Query was: '$sQuery'",
                        $oDb->errno
                    );
            }
        }
    }

    /**#@+
     *
     * @param mixed $mParams,...
     */

    public function execute() {
        $this->_execute(func_get_args());
        $this->_done();
    }

    /**
     * @return null|bool|int|string|float
     */
    public function getOne() {
        $this->_execute(func_get_args());
        $this->_fetchRow();
        if(isset($this->aResultSet[0][$this->aFieldnames[0]])) {
            return $this->aResultSet[0][$this->aFieldnames[0]];
        }
        return null;
    }

    /**
     * @return array
     */
    public function getCol() {
        $this->_execute(func_get_args());
        $this->_fetchAll();
        $sIndex = $this->aFieldnames[0];
        $aReturn = array();
        foreach($this->aResultSet as $aResultRow) {
            $aReturn[] = $aResultRow[$sIndex];
        }
        return $aReturn;
    }

    /**
     * @return array
     */
    public function getRow() {
        $this->_execute(func_get_args());
        $this->_fetchRow();
        if(isset($this->aResultSet[0])) {
            return $this->aResultSet[0];
        }
        return array();
    }

    /**
     * @return array
     */
    public function getAssoc() {
        $this->_execute(func_get_args());
        $this->_fetchAll();
        if(isset($this->aFieldnames[0]) && isset($this->aFieldnames[1])) {
            $sIndexKey = $this->aFieldnames[0];
            $sIndexValue = $this->aFieldnames[1];
            $aReturn = array();
            foreach($this->aResultSet as $aResultRow) {
                $aReturn[$aResultRow[$sIndexKey]] = $aResultRow[$sIndexValue];
            }
            return $aReturn;
        }
        return array();
    }

    /**
     * @return array
     */
    public function getAll() {
        $this->_execute(func_get_args());
        $this->_fetchAll();
        return $this->aResultSet;
    }
    /**#@-*/

    /**
     * @return false|int
     */
    public function numRows() {
        return $this->iNumRows;
    }

    /**
     * @return int
     */
    public function affectedRows() {
        return $this->oStatement->affected_rows;
    }

    /**
     * @return int
     */
    public function lastInsertId() {
        return $this->oStatement->insert_id;
    }

    public function getLastExecutedQuery() {
        $sReturn = $this->sQuery;
        if($this->aArgs) {
            $sReturn .= "; -- Argumente: ~".implode("~,~", $this->aArgs)."~";
        }
        return $sReturn;
    }

    /**
     * @throws DbException
     *
     * @param array $aArgs
     */
    private function _execute($aArgs) {
        $aArgs = $this->_parseFuncArgs($aArgs);
        $this->aArgs = $aArgs;
        $iArgs = count($aArgs);
        if($iArgs) {
            if($this->oStatement->param_count !== $iArgs ) {
                throw new DbException(
                    "Inserting parameters failed: ".$this->oStatement->param_count.
                    " Parameters expected but ".$iArgs." passed."
                );
            }
            $aRefArgs = array();
            foreach(array_keys($aArgs) as $mIndex) {
                $aRefArgs[$mIndex] = &$aArgs[$mIndex];
            }
            array_unshift($aRefArgs, str_repeat("s", $iArgs));
            // Needs References
            call_user_func_array(array($this->oStatement, "bind_param"), $aRefArgs);
        }
        $bWorked = $this->oStatement->execute();
        if($bWorked === false) {
            $sError = sprintf(
                "Query failed: %s (%s) Query was: '%s'",
                $this->oStatement->error,
                $this->oStatement->errno,
                $this->sQuery
            );
            switch($this->oStatement->errno) {
                case 1062:
                    throw new DbKeyViolationException($sError, $this->oStatement->errno);
                default:
                    throw new DbException($sError, $this->oStatement->errno);
            }

        }

        $this->_prepareFetch();
    }

    private function _prepareFetch() {
        if($this->bMetadata && !$this->bPreparedFetch) {
            $oMeta = $this->oStatement->result_metadata();
            if($oMeta === false) {
                $this->bMetadata = false;
            } else {
                $this->_prepareMetadata($oMeta);

                $this->aResultRow = array_fill(0, count($this->aFieldnames), null);
                // Ugly but 'bind_result' forces you to pass references
                $aRefs = array();
                foreach ($this->aResultRow as $iIndex => &$rmValue) {
                    $aRefs[$iIndex] = &$rmValue;
                }

                call_user_func_array(array($this->oStatement, "bind_result"), $this->aResultRow);
                $this->bPreparedFetch = true;
            }
        }
    }

    /**
     * @param mysqli_result $oMeta
     */
    private function _prepareMetadata(mysqli_result $oMeta) {
        $aFields = $oMeta->fetch_fields();
        foreach($aFields as $oField) {
            $this->aFieldnames[] = $oField->name;
        }
    }

    private function _fetchRow() {
        $this->_fetch(true);
    }

    private function _fetchAll() {
        $this->_fetch(false);
    }

    /*
     * @param bool $bOne One line ?
     */
    private function _fetch($bOne) {
        $this->aResultSet = array();
        if($bOne !== true) {
            $this->oStatement->store_result();
        }
        while($this->oStatement->fetch()) {

            // Deref
            $aTmp = array();
            foreach($this->aResultRow as $mValue) {
                $aTmp[] = $mValue;
            }
            $this->aResultSet[] = array_combine($this->aFieldnames, $aTmp);

            if($bOne === true) {
                break;
            }
        }

        $this->iNumRows = $this->oStatement->num_rows;
        $this->_done();
    }

    private function _done() {
        $this->oStatement->free_result();
    }

    /**
     * @param array $aArgs
     * @return array
     */
    private function _parseFuncArgs($aArgs) {
        if(isset($aArgs[0]) && is_array($aArgs[0])) {
            return $aArgs[0];
        }
        return $aArgs;
    }

}

Уродливые биты (я думаю, thats, почему мы здесь, я думаю :) ) в _execute и _prepareFetch как в mysqli API и заставили нас использовать ссылки.

Класс принимает на веру, что прошли в объект mysqli, то уже подключен к базе данных.

Если я что-то пропустил, дайте мне знать.



697
18
задан 21 января 2011 в 08:01 Источник Поделиться
Комментарии