webForumDet fria alternativet

PDO Wrapper class, fatal error.

5 svar · 1 592 visningar · startad av Renegade8164

Renegade8164Medlem sedan sep. 201057 inlägg
#1

Hej jag har skapat en wrapper klass till PDO-anslutningen, men jag får fatall error när jag försöker hänta data med den från databasen. Jag använder mig utav php 5.3.2.

db.class.php

<?php
/**
 * Database wrapper for PDO
 *
 */
class db extends PDO
{
    public $html = null;

    private $_error;
    private $_sql;
    private $_bind;
    private $_errorCallbackFunction;
    private $_errorMsgFormat;

    /**
     * Try to connect to database with PDO
     *
     * @param string $dsn
     * @param string $user
     * @param string $pass
     * @param array  $options
     */
    public function __construct($dsn, $user, $pass, $options="")
    {
        
        // Set default options
        $options = array(
            PDO::ATTR_PERSISTENT => true,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        // Try to connect to datase
        try {

            // Create new PDO object
            parent::__construct($dsn, $user, $pass, $options);

        } catch (PDOException $e) {

            // Add error exception to private variable
            $this->_error = $e->getMessage();

        }

    }

    /**
     * Debuggning PDO error handler
     *
     * @return string
     */
    private function debug() {

        if (!empty($this->_errorCallbackFunction)) {

            $error = array("Error" => $this->_error);

            // Check if sql query is not empty
            if (!empty($this->_sql)) {
                $error["SQL Statement"] = $this->_sql;

            }

            // Check if any binding exists
            if (!empty($this->_bind)) {
                $error["Bind Parameters"] = trim(print_r($this->_bind, true));
            }

            // Generate backtrace
            $backtrace = debug_backtrace();

            // Create backtrace information
            if (!empty($backtrace)) {
                foreach($backtrace as $info) {
                    if ($info["file"] != __FILE__) {
                        $error["Backtrace"] = $info["file"]." @ ".$info["line"];
                    }
                }
            }

            // Check if error-message format is html
            if ($this->_errorMsgFormat == "html") {

                // Check if any bind errors exist
                if (!empty($error["Bind Parameters"])) {
                    $error["Bind Parameters"] = "<pre>".$error["Bind Parameters"]."</pre>";
                }

                // Get stylesheet file
                $css  = trim(file_get_contents(dirname(__FILE__)."/error.css"));

                // html error output
                $this->html  = "<style>\n$css\n</style>\n";
                $this->html .= '<div class="db-error">';"\n<h3>SQL Error</h3>";
                $this->html .= '<table><thead>';
                $this->html .= '<tr><th>Key</th><th>Value</th></tr></thead>';
                $this->html .= '<tbody><tr>';
                foreach ($error as $key => $val) {
                    $this->html .= "<td>$key</td>\n<td>$val</td>";
                }
                $this->html .= "</tr></tbody></table></div>";
            }
            // Else if message-format is html
            elseif($this->_errorMsgFormat == "text") {
                $msg .= "SQL Error\n" . str_repeat("-", 50);
                foreach($error as $key => $val)
                    $msg .= "\n\n$key:\n$val";
            }

            return $this->_errorCallbackFunction($msg);
        } else {
            return false;
        }
    }

    /**
     * Delete data from database
     *
     * @param string $table
     * @param string $where
     * @param array  $bind
     * @return boolean
     */
    public function delete($table, $where, $bind="") {

        // Crate database query
        $sql = "DELETE FROM " . $table . " WHERE " . $where . ";";

        // Run query
        if ($this->run($sql, $bind)) {

            // If everything went fine, return true
            return true;
        }
        else {
            // If an error occurred in the process, return false
            return false;
        }

    }

    /**
     * Filter data
     *
     * @param string $table
     * @param string $info
     * @return array
     */
    private function filter($table, $info) {

        // Collect pdo driver data
        $driver = $this->getAttribute(PDO::ATTR_DRIVER_NAME);

        // If using SQLite as driver
        if ($driver == 'sqlite') {
            $sql = "PRAGMA table_info('" . $table . "');";
            $key = "name";
        }
        // If using MySQL as driver
        else if ($driver == 'mysql') {
            $sql = "DESCRIBE " . $table . ";";
            $key = "Field";
        }
        // For all other driver
        else {
            $sql = "SELECT 
                        column_name
                    FROM
                        information_schema.columns
                    WHERE table_name = '" . $table . "';";
            $key = "column_name";
        }

        // Check if value is false
        if (false !== ($list = $this->run($sql))) {

            // Create array
            $fields = array();

            // Save list values in $fields array
            foreach ($list as $record) {
                $fields[] = $record[$key];
            }
            return array_values(array_intersect($fields, array_keys($info)));
        }
        return array();
    }

    /**
     * Clean up array
     *
     * @param array $bind
     * @return array
     */
    private function cleanup($bind) {

        // Check if isn't an array
        if(!is_array($bind)) {

            // Check if the variable is empty
            if (!empty($bind)) {
                $bind = array($bind);
            }
            // Else create an array
            else {
                $bind = array();
            }
        }
        return $bind;
    }

    /**
     * Insert data into database
     *
     * @param <type> $table
     * @param <type> $info
     * @return <type>
     */
    public function insert($table, $info) {

        // Filter table and info
        $fields = $this->filter($table, $info);

        // Create sql query
        $sql  = "INSERT INTO ".$table." (".implode($fields, ", ");
        $sql .= ") VALUES (:".implode($fields, ", :").");";

        // Create an array for bindings
        $bind = array();

        // Add table and info variables to array
        foreach ($fields as $field) {
            $bind[":$field"] = $info[$field];
        }

        return $this->run($sql, $bind);
    }

    /**
     * Execute SQL query
     *
     * @param string $sql
     * @param string $bind
     * @return mixed
     */
    public function run($sql, $bind="") {
        
        // Declare no errors
        $this->_error = null;

        // Trim query
        $this->_sql = trim($sql);

        // Clean up
        $this->_bind = $this->cleanup($bind);
        
        // Try execute sql query
        try {

            // Prepare query
            $stmt = $this->prepare($this->_sql);

            // If binding execution not fails
            if ($stmt->execute($this->_bind) !== false) {

                // Match 'select', 'describe' or 'pragma' in query
                if (preg_match("/^(" .
                        implode("|",
                                array(
                                    "select",
                                    "describe",
                                    "pragma")) . ") /i", $this->_sql)) {
                    
                    // Return array fetch all
                    return $stmt->fetchAll(PDO::FETCH_ASSOC);
                    
                }
                // Match 'delete', 'insert' or 'update' in query
                else if (preg_match("/^(".
                        implode("|",
                                array(
                                    "delete",
                                    "insert",
                                    "update")) . ") /i", $this->_sql)) {
                    
                    // Return row count
                    return $stmt->rowCount();

                }
            }

        // Catch any exceptions
        } catch (PDOException $e) {

            // Get error message
            $this->_error = $e->getMessage();

            // Get debugging
            $this->debug();

            return false;
        }

    }

    /**
     * Select data from database
     *
     * @param string $table
     * @param string $where
     * @param string $bind
     * @param string $fields
     * @return mixed
     */
    public function select($table, $where="", $bind="", $fields="*") {

        // Create 'SELECT' query
        $sql = "SELECT " . $fields . " FROM " . $table;

        // Check if any WHERE statements
        if (!empty($where)) {
            $sql .= " WHERE " . $where;
        }

        // End sql query
        $sql .= ";";
        
        // Return execute query
        return $this->run($sql, $bind);
    }

    /**
     * Set error callback function
     *
     * @param string $errorCallbackFunction
     * @param string $errorMsgFormat
     * @return string
     */
    public function setErrorCallbackFunction($errorCallbackFunction,
            $errorMsgFormat="html") {

        // Variable functions for won't work with language constructs such as
        // echo and print, so these are replaced with print_r.
        if(in_array(strtolower($errorCallbackFunction), 
            array("echo", "print"))){
            $errorCallbackFunction = "print_r";
        }

        // Check if function exists
        if(function_exists($errorCallbackFunction)) {

            // Collect callback function data
            $this->_errorCallbackFunction = $errorCallbackFunction;

            // If $errorMsgFormat isn't either html or text , default html
            if(!in_array(strtolower($errorMsgFormat), array("html", "text"))) {
                $errorMsgFormat = "html";
            }

            // Return error message
            return $this->_errorMsgFormat = $errorMsgFormat;
        }

    }

    /**
     * Update data in database
     *
     * @param string $table
     * @param string $info
     * @param string $where
     * @param string $bind
     * @return mixed
     */
    public function update($table, $info, $where, $bind="") {

        // Collect filter data
        $fields = $this->filter($table, $info);

        // Calculate size of array
        $fieldSize = sizeof($fields);

        // Create update query string
        $sql = "UPDATE " . $table . " SET ";

        // Loop adding query from array
        for ($f = 0; $f < $fieldSize; ++$f) {

            // If array hold more then one value
            if ($f > 0) {
                $sql .= ", ";
            }

            // Add query string
            $sql .= $fields[$f] . " = :update_" . $fields[$f];

        }

        // End query string
        $sql .= " WHERE " . $where . ";";

        // Cleanup bindings
        $bind = $this->cleanup($bind);

        // Loop update array
        foreach ($fields as $field) {
            $bind[":update_$field"] = $info[$field];
        }

        // Return execute process
        return $this->run($sql, $bind);

    }
    
}

Sen på min index.php test-sida för tillfälligt har jag denna kod;

<?php
// Aktivera felrapportering
error_reporting(E_ALL);
// Hämta configs
$app = parse_ini_file('configs/application.ini');

// Hämta klass 
require_once '../resources/class/db.class.php';

// Definiera DSN med config-variablerna
$dsn  = $app['db.type'];':host='.$app['db.host'].';';
$dsn .= 'port='.$app['db.port'].';';
$dsn .= 'dbname='.$app['db.name'];

// Skapa ny databas anslutning
$db = new db($dsn, $app['db.user'], $app['db.pass']);

// Denna kör koden; 'SELECT' * FROM 'users' och sparar till $results
// Denna raden skapar problemet!!
$results = $db->select("users");

När jag kör min kod får jag detta problemet:

Fatal error: Call to a member function select() on a non-object in index.php on line 20

Vad är det som skapar detta problemet och hur löser man det?, jag skapade väll ett pdo-objekt i konstruktorn?

doridoriMedlem sedan juni 2006338 inlägg
#2

Jag är långt ifrån någon PHP-expert, så jag chansar:

Är du säker på att db-instansen skapas?
För i mina ögon gör du inte något för att kolla $db->error, prova printa ut den för säkerhets skull?

Edit:
Sen är det standard att börja klassnamn med stor bokstav. I ditt fall hade jag skrivit DB.

Nate.AMedlem sedan mars 2006280 inlägg
#3

Du har ju en debug-metod, kör den efter anslutningen så ser du ju om något blivit fel?

jmeMedlem sedan maj 20011 967 inlägg
#4

Hmm, att köra try-catch i konstruktorn ser i mina ögon tokdåligt ut. Jag skulle istället:

try
{
    $db = new db(...)    
}
catch(Exception $e)
{
    //skriv ut felmeddelandet här
}
Renegade8164Medlem sedan sep. 201057 inlägg
#5

doridori skrev:

Jag är långt ifrån någon PHP-expert, så jag chansar:

Är du säker på att db-instansen skapas?
För i mina ögon gör du inte något för att kolla $db->error, prova printa ut den för säkerhets skull?

Edit:
Sen är det standard att börja klassnamn med stor bokstav. I ditt fall hade jag skrivit DB.

Jag tror det kan vara problemet att den inte skapas, men jag ser inte problemet varför instansen inte skulle skapas och när jag testar db->error så får jag Fatal error:

Fatal error: Call to a member function error() on a non-object...

...

Nate.A skrev:

Du har ju en debug-metod, kör den efter anslutningen så ser du ju om något blivit fel?

Jag får samma typ av problem

Fatal error: Call to a member function debug() on a non-object...

jme skrev:

Hmm, att köra try-catch i konstruktorn ser i mina ögon tokdåligt ut. Jag skulle istället:

try
{
    $db = new db(...)    
}
catch(Exception $e)
{
    //skriv ut felmeddelandet här
}

Jag försökte det med nu, men halv inga resultat eller outputs.

Renegade8164Medlem sedan sep. 201057 inlägg
#6

Tack för hjälpen de som försökt lösa problemet (då det är ganska få vad jag vet som faktiskt använder PDO), men det var inget problem med klassen. Jag löste det genom att skriva om den tillfälliga index.php-sidan. Jag hade bara gjort ett dumt misstag i $dsn variablen att sluta raden med ett semikolon istället för en konkategonering. (Använder mig utav marginal på 80 tecken)

Jag ändrade denna:

$dsn  = $app['db.type'];':host='.$app['db.host'].';';

till:

$dsn  = $app['db.type'].':host='.$app['db.host'].';';
Genererad på 372 ms · cache AV · v20260730165559-full.f96bc7eb