SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Extending a class from the class which is extended from mysqli

    Hi,

    I am not sure if this is possible as I am not very good in OOP programming yet.

    I have this db class extended from mysqli,

    PHP Code:
    class database extends mysqli
        
    {
            
    # overwrite parent __construct
            
    public function __construct($hostname null,$username null,$password null,$database null,$port null$socket null)
            {
                
    $hostname $hostname !== null $hostname ini_get("mysqli.default_host");
                
    $username $username !== null $username ini_get("mysqli.default_user");
                
    $password $password !== null $password ini_get("mysqli.default_pw");
                
    $database $database !== null $database "";
                
    $port     $port     !== null $port     ini_get("mysqli.default_port");
                
    $socket   $socket   !== null $socket   ini_get("mysqli.default_socket");
                
                
    parent::__construct($hostname,$username,$password,$database,$port,$socket);
        
                
    # check if connect errno is set
                
    if (mysqli_connect_errno()) 
                {
                    throw new 
    RuntimeException('Cannot access database: ' mysqli_connect_error());
                }
                
            }
     
             
            
    # fetches all result rows as an associative array, a numeric array, or both
            # mysqli_fetch_all (PHP 5 >= 5.3.0)
            
    public function fetch_all($query
            {
                
    $result parent::query($query);
                if(
    $result
                {
                    
    # check if mysqli_fetch_all function exist or not
                    
    if(function_exists('mysqli_fetch_all')) 
                    {
                        
    # NOTE: this below always gets error on certain live server
                        # Fatal error: Call to undefined method mysqli_result::fetch_all() in /.../class_database.php on line 28
                        
    return $result->fetch_all(MYSQLI_ASSOC);
                    }
                    
                    
    # fall back to use while to loop through the result using fetch_assoc
                    
    else
                    {
                        while(
    $row $result->fetch_assoc())
                        {
                            
    $return_this[] = $row;
                        }
        
                        if (isset(
    $return_this))
                        {
                            return 
    $return_this;
                        }
                        else
                        {
                            return 
    false;
                        }
                    }
                }
                else
                {
                    return 
    self::get_error();
                }
            }
            
            
    # fetch a result row as an associative array
            
    public function fetch_assoc($query)
            {
                
    $result parent::query($query);
                if(
    $result
                {
                    return 
    $result->fetch_assoc();
                } 
                else
                {
                    
    # call the get_error function
                    
    return self::get_error();
                    
    # or:
                    # return $this->get_error();
                
    }
            }
            
            ...
        
            
    # display error
            
    public function get_error() 
            {
                if(
    $this->errno || $this->error)
                {
                    return 
    sprintf("Error (%d): %s",$this->errno,$this->error);
                }
            }
            
            public function 
    __destruct()
            {
               
    parent::close();
                
    //echo "Destructor Called";
            
    }
        } 

    and I have this procedural style of code which I want to turn it into a class that extended from the database class above,

    PHP Code:
    if(isset($_REQUEST['search'])) $search $_REQUEST['search'];
        
        
    $sql "
        SELECT *
        
        FROM root_pages
            
        WHERE root_pages.pg_cat_id = '2'
        AND root_pages.parent_id != root_pages.pg_id
        AND root_pages.pg_hide != '1'
        AND root_pages.pg_url != 'cms'
        AND root_pages.pg_content_1 LIKE '%"
    .$search."%'
        OR root_pages.pg_content_2 LIKE '%"
    .$search."%'
        
        AND root_pages.pg_content_1 NOT LIKE '%http://%'
        AND root_pages.pg_content_2 NOT LIKE '%http://%'
        
        ORDER BY root_pages.pg_created DESC
        "
    ;
        
        
    # use the stored connection object from the class_page_controller.php, to process the query
        
    $items $connection->fetch_all($sql);
        
    $total_item $connection->num_rows($sql); 
    so I think, by theory I can extend this code into a class like this,

    PHP Code:
     class search extends database
        
    {

        public 
    $search null;
           
        public function 
    __construct($keyword)
        {
           
    $this->search $keyword;    
        }
        
        
        public function 
    get_result()
        {
        
    $sql "
        SELECT*
        
        FROM root_pages
            
        WHERE root_pages.pg_cat_id = '2'
        AND root_pages.parent_id != root_pages.pg_id
        AND root_pages.pg_hide != '1'
        AND root_pages.pg_url != 'cms'
        AND root_pages.pg_content_1 LIKE '%"
    .$this->search."%'
        OR root_pages.pg_content_2 LIKE '%"
    .$this->search."%'
        
        AND root_pages.pg_content_1 NOT LIKE '%http://%'
        AND root_pages.pg_content_2 NOT LIKE '%http://%'
        
        ORDER BY root_pages.pg_created DESC
        "
    ;
        
        
    $items parent::fetch_all($sql);
        
        return 
    $items;
          }
        } 
    then I call the object of search,

    PHP Code:
     $output = new search('1');
        
    print_r($output->get_result()); 
    but I get lots of errors instead,

    Code:
    > Warning: mysqli::query()
    > [mysqli.query]: Couldn't fetch search
    > in C:\wamp\www\xxx\class_database.php
    > on line xx
    > 
    > Warning: database::get_error()
    > [database.get-error]: Couldn't fetch
    > search in
    > C:\wamp\www\xxx\class_database.php on
    > line xx
    > 
    > Warning: mysqli::close()
    > [mysqli.close]: Couldn't fetch search
    > in C:\wamp\www\xxx\class_database.php
    > on line xx
    When I tried to call the child class (search) from the parent class (database) in this way,

    PHP Code:
    $database = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME);
        
    print_r(search::get_result()); 
    then I get this error,

    Code:
    > Fatal error: Non-static method
    > mysqli::query() cannot be called
    > statically in
    > C:\wamp\www\xxx\class_database.php on
    > line
    Sigh...

    What have I done incorrectly? How can I fix it? Any ideas?

    Thanks.

  2. #2
    SitePoint Guru aamonkey's Avatar
    Join Date
    Sep 2004
    Location
    kansas
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    #1 - To simply avoid the error you would use $items = $this->fetch_all($sql), not parent::fetch_all($sql)....but more importantly:

    #2 - I don't see the point in extending mysqli. Your search class should not extend your database class - A search USES a database, it's not a child of it - just like a carpenter USES a hammer, he is not the same type of thing as a hammer. Pass the database object to the class in the constructor (sort of like handing the hammer to the carpenter) like this:

    Code PHP:
    <?php
     
    class search
    {
     
        public $database;
     
        public function __construct(database $database)
        {
           $this->database = $database;    
        }
     
     
        public function get_result($keyword)
        {
            $sql = "
            SELECT*
     
            FROM root_pages
     
            WHERE root_pages.pg_cat_id = '2'
            AND root_pages.parent_id != root_pages.pg_id
            AND root_pages.pg_hide != '1'
            AND root_pages.pg_url != 'cms'
            AND root_pages.pg_content_1 LIKE '%".$keyword."%'
            OR root_pages.pg_content_2 LIKE '%".$keyword."%'
     
            AND root_pages.pg_content_1 NOT LIKE '%[url]http://%[/url]'
            AND root_pages.pg_content_2 NOT LIKE '%[url]http://%[/url]'
     
            ORDER BY root_pages.pg_created DESC
            ";
     
            $items = $this->database->fetch_all($sql);
     
            return $items;
        }
    }

    #3 - your query is very susceptible to an sql injection - you should be using bound parameters
    aaron-fisher.com - PHP articles and more

  3. #3
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aamonkey View Post
    #1 - To simply avoid the error you would use $items = $this->fetch_all($sql), not parent::fetch_all($sql)....but more importantly:

    #2 - I don't see the point in extending mysqli. Your search class should not extend your database class - A search USES a database, it's not a child of it - just like a carpenter USES a hammer, he is not the same type of thing as a hammer. Pass the database object to the class in the constructor (sort of like handing the hammer to the carpenter) like this:

    Code PHP:
    <?php
     
    class search
    {
     
        public $database;
     
        public function __construct(database $database)
        {
           $this->database = $database;    
        }
     
     
        public function get_result($keyword)
        {
            $sql = "
            SELECT*
     
            FROM root_pages
     
            WHERE root_pages.pg_cat_id = '2'
            AND root_pages.parent_id != root_pages.pg_id
            AND root_pages.pg_hide != '1'
            AND root_pages.pg_url != 'cms'
            AND root_pages.pg_content_1 LIKE '%".$keyword."%'
            OR root_pages.pg_content_2 LIKE '%".$keyword."%'
     
            AND root_pages.pg_content_1 NOT LIKE '%[url]http://%[/url]'
            AND root_pages.pg_content_2 NOT LIKE '%[url]http://%[/url]'
     
            ORDER BY root_pages.pg_created DESC
            ";
     
            $items = $this->database->fetch_all($sql);
     
            return $items;
        }
    }

    #3 - your query is very susceptible to an sql injection - you should be using bound parameters
    Thank you very much for this! can I ask what you mean by 'bound parameters'? Any examples of this kind?

    Mind if I ask - what is wrong with parent::fetch_all($sql) as I thought I am extending from mysqli class and I want to access
    Code:
    fetch_all
    from the parent class which is mysqli?

    Thanks.

  4. #4
    SitePoint Guru aamonkey's Avatar
    Join Date
    Sep 2004
    Location
    kansas
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lauthiamkok View Post
    Thank you very much for this! can I ask what you mean by 'bound parameters'? Any examples of this kind?
    You want to look at prepared statements - there is a good example in the php mysqli manual


    Quote Originally Posted by lauthiamkok View Post
    Mind if I ask - what is wrong with parent::fetch_all($sql) as I thought I am extending from mysqli class and I want to access
    Code:
    fetch_all
    from the parent class which is mysqli?

    Thanks.
    When you extend a class, the child class acts inherits all of the methods of it's parent, so calling a method in the child class is the same as calling it in the parent class - i.e. $this->doStuff(). parent:: is used to access static variables and methods of the parent class, or within a child class method which overrides the parent method to call the parent method - i.e.:

    Code PHP:
    class foo
    {
        function bar()
        {
            echo 'called from foo<br />';
        }
    }
     
     
    class foo2 extends foo
    {
     
        function bar()
        {
            echo 'called from foo2<br />';
            parent::bar();
        }
    }
     
    $foo2 = new foo2;
    $foo2->bar();
    will output:
    called from foo2
    called from foo

    there's a good explanation in the manual:
    http://us3.php.net/manual/en/languag...ekudotayim.php

    hope that makes sense - cheers
    aaron-fisher.com - PHP articles and more

  5. #5
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aamonkey View Post
    You want to look at prepared statements - there is a good example in the php mysqli manual




    When you extend a class, the child class acts inherits all of the methods of it's parent, so calling a method in the child class is the same as calling it in the parent class - i.e. $this->doStuff(). parent:: is used to access static variables and methods of the parent class, or within a child class method which overrides the parent method to call the parent method - i.e.:

    Code PHP:
    class foo
    {
        function bar()
        {
            echo 'called from foo<br />';
        }
    }
     
     
    class foo2 extends foo
    {
     
        function bar()
        {
            echo 'called from foo2<br />';
            parent::bar();
        }
    }
     
    $foo2 = new foo2;
    $foo2->bar();
    will output:
    called from foo2
    called from foo

    there's a good explanation in the manual:
    http://us3.php.net/manual/en/languag...ekudotayim.php

    hope that makes sense - cheers
    Yes it does make sense. I will go and read the documentation from your links. Thank you very much!

  6. #6
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aamonkey View Post
    You want to look at prepared statements - there is a good example in the php mysqli manual
    Sorry, can I ask - how can I turn my search class with a prepared and bound statement?

    I have read some articles online why we should use prepared statements,
    http://www.adamsinfo.com/php-mysql-d...sql-injection/
    http://forum.codecall.net/php-tutori...tatements.html

    But I still don't have a clue how to improve my query... I tried with this amendment below,

    PHP Code:
    class search
    {
        
        public 
    $mysqli null;
            
        public function 
    __construct($mysqli)
        {
           
    $this->mysqli $mysqli;
        }
        
        public function 
    get_result($parameter)
        {
            
    $sql "
            SELECT *
            FROM root_contacts_cfm
            WHERE root_contacts_cfm.cnt_id = '?'
            ORDER BY cnt_id DESC
            "
    ;
            
            
    $stmt $this->mysqli->prepare($sql);
            
            
    /* bind parameters for markers */
            
    $stmt->bind_param("s"$parameter);
            
            
    /* execute query */
            
    $stmt->execute();
            
             
    /* fetch value */
            
    return $stmt->fetch();
            
        }

    I will get this error,

    Warning: mysqli_stmt::bind_param() [mysqli-stmt.bind-param]: Number of variables doesn't match number of parameters in prepared statement in C:\wamp\www\xxxl\class_database.php on line 487

    line 487 refers to
    PHP Code:
    $stmt->bind_param("s"$parameter); 
    Thanks.

  7. #7
    SitePoint Guru aamonkey's Avatar
    Join Date
    Sep 2004
    Location
    kansas
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Almost there - you just need to remove the singles quote around ?. i.e.:
    Code PHP:
    $sql = " 
            SELECT * 
            FROM root_contacts_cfm 
            WHERE root_contacts_cfm.cnt_id = ?
            ORDER BY cnt_id DESC 
            ";
    aaron-fisher.com - PHP articles and more

  8. #8
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aamonkey View Post
    Almost there - you just need to remove the singles quote around ?. i.e.:
    Code PHP:
    $sql = " 
            SELECT * 
            FROM root_contacts_cfm 
            WHERE root_contacts_cfm.cnt_id = ?
            ORDER BY cnt_id DESC 
            ";
    Thanks. It now returns 1 instead of fetching and returning data from the query...

    Is it something wrong in my database class?

  9. #9
    SitePoint Guru aamonkey's Avatar
    Join Date
    Sep 2004
    Location
    kansas
    Posts
    953
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm not familiar with mysqli (I use PDO), but I would guess $stmt->fetch() is returning true (1) on success - I'd look up the fetch method in the manual and go from there. Maybe someone more familiar with it can help.

    edit - just checked out the manual on that method and it looks as though you need to bind the variables and do a while loop over the results.
    aaron-fisher.com - PHP articles and more

  10. #10
    SitePoint Evangelist
    Join Date
    Dec 2008
    Location
    Plymouth, United Kingdon
    Posts
    449
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by aamonkey View Post
    I'm not familiar with mysqli (I use PDO), but I would guess $stmt->fetch() is returning true (1) on success - I'd look up the fetch method in the manual and go from there. Maybe someone more familiar with it can help.

    edit - just checked out the manual on that method and it looks as though you need to bind the variables and do a while loop over the results.
    Thanks. I will have a look and try it again


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •