SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 28
  1. #1
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Problem with mysqli wrapper class

    I'm having some problems with a fetch method in my MySQLi wrapper class.

    an extract from the class

    PHP Code:
        private function _bindResult()
        {
            
    $this->_metaData $this->_statement->result_metadata();
            while (
    $field $this->_metaData->fetch_field()) {
                
    $this->_fieldParams[] = &$this->_fieldRow[$field->name];
            }

            
    call_user_func_array(array($this->_statement'bind_result'), $this->_fieldParams);
        }

        public function 
    fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_fieldRow
        } 
    and usage

    PHP Code:
    while ($res $stmt->fetchRow()) {
        
    var_dump($res);

    this works fine but because a reference to $this->_fieldRow is returned if do this

    PHP Code:
    while ($res $stmt->fetchRow()) {
        
    $result[] = $res;
    }
    var_dump($result); 
    I get the last result repeated

    I need to find a way to force the fetchRow method to return a value not a reference. I can achieve using str_replace (i know copies the value) like this

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;
            
    $row str_replace(''''$this->_fieldRow); //pass by value, there must be a better way!!!
            
    return $row;
        } 
    but there got to be a better/right way to do this. that code is just plain stupid

    Any help would be great

    Best Regards, George
    Last edited by GOPalmer; May 31, 2009 at 07:14.

  2. #2
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    no ideas?

  3. #3
    SitePoint Wizard
    Join Date
    Nov 2005
    Posts
    1,191
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hard to tell what's going on from what you posted.
    because a reference to $row is returned if do this
    ...
    I get the last result repeated
    That doesn't make much sense, sounds more like a logic error in the wrapper.

  4. #4
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry i wasn't very clear.

    In the _bindResult method i'm passing a reference of $this->_fieldRow to mysqli_stmt::bind_result.

    When i iterate over the fetchRow method, reference to $this->_fieldRow is returned. This is causing problems because when i iterate a second time $this->_fieldRow over written.

    I need to find a way to return a copy of $this->_fieldRow's value from fetchRow() rather than a reference to it. The only way i know of it to copy the string using something like str_replace. Can you think of another way or am i just doing it plain wrong?

    Best Regards, George

  5. #5
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry to bump this up again but really need to sort this out. Has any one got any ideas?

  6. #6
    SitePoint Wizard
    Join Date
    Nov 2005
    Posts
    1,191
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    As you have it, _fieldRow should be returned by value, so I'm guessing the problem is elsewhere in code not posted.

    Sorry, perhaps I'm missing something, but since no-one else has posted either ...

  7. #7
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for trying. $this->_fieldRow is only used in the posted code. I think the issue originates from here

    $this->_fieldParams[] = &$this->_fieldRow[$field->name];

    but it must be passed by ref at this point.

  8. #8
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Why do you use _fieldRow as an array?

    &$this->_fieldRow[$field->name];

  9. #9
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    it has the same affect as doing this

    $stmt->bind_result($this->_fieldRow['id'], $this->_fieldRow['title'], $this->_fieldRow['etc']);

    It means i can bind the result to an array rather than separate variables like this.

    $stmt->bind_result($id, $title, $etc);

    Best Regards, George

  10. #10
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Oh ok, I didn't realize str_replace() will iterate over the elements in an array.

    If an array contains references as its elements, even if you copy the array(which you do when you return from fetchRow()), php will keep using those same references.
    PHP Code:
    $a 'a';
    $arr = array(&$a);
    $arrcopy $arr;
    print_r($arrcopy);
    $a 'changed';
    print_r($arrcopy); // 'changed'! 
    You could just run a loop to do a manual copy
    PHP Code:
    $copy = array();
    foreach (
    $this->_fieldRow as $k => $v) {
       
    $copy[$k] = $v;
    }
    return 
    $copy
    Although, maybe you shouldn't be using bind_result in the first place.

  11. #11
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    >>Although, maybe you shouldn't be using bind_result in the first place.

    If i shouldn't be using bind_result what are my options? I sure thats the only way.

  12. #12
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    how about array_slice() to create a copy?

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    array_slice($this->_fieldRow,0,null,true); 
        } 
    Alternatively you could isolate the keys and values then merge them together into another array.

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    array_combine(array_keys($this->_fieldRow),array_values($this->_fieldRow));
        } 
    I would also isolate this into a separate method:

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_makeCopy();
        } 
     

    protected function 
    _makeCopy() {

     return  
    array_combine(array_keys($this->_fieldRow),array_values($this->_fieldRow));



  13. #13
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    oddz, thanks for the suggestions but neither of those functions copy the value, a reference is still returned.

    Its a real shame because its works exactly as i need it to with str_replace in there but i know it just not right.

  14. #14
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by GOPalmer View Post
    If i shouldn't be using bind_result what are my options? I sure thats the only way.
    I always use pdo, and forget mysqli statements force you to use bound variables for output.

  15. #15
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    >>I always use pdo, and forget mysqli statements force you to use bound variables for output.

    I would prefer to use pdo but the project requirements are that i use both mysqli and mysql (with emulated prepared statements) wrappers. The client wants identical interfaces to both mysql and mysqli so working with bind_result in this rather odd maner is a sacrifice thats i must make. I just really want to get arround that horible str_replace

  16. #16
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    That is because the values are being references not the array.

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_makeCopy();
        } 
     

    protected function 
    _makeCopy() {

      
    $data = array();
      foreach(
    $this->_fieldRow as $key=>$row$data[$key] = $value;
      return 
    $data;



  17. #17
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    the str_replace() might be a one liner, but foreach will maintain the variables type. for example, a null won't get cast to empty string.

  18. #18
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by GOPalmer
    I would prefer to use pdo but the project requirements are that i use both mysqli and mysql (with emulated prepared statements) wrappers. The client wants identical interfaces to both mysql and mysqli so working with bind_result in this rather odd maner is a sacrifice thats i must make. I just really want to get arround that horible str_replace
    I haven't used MySQLI in a long while but I'm about 100% certain binding the result variables isn't required.

  19. #19
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I took a quick look at the docs, and for prepared statements, it does actually look like you need to bind_result :/

  20. #20
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    You can use data_seek alongside fetch_assoc().

  21. #21
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    That is because the values are being references not the array.

    PHP Code:
        public function fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_makeCopy();
        } 
     

    protected function 
    _makeCopy() {

      
    $data = array();
      foreach(
    $this->_fieldRow as $key=>$row$data[$key] = $value;
      return 
    $data;



    oddz, yes that works. I'm a little worried about the overhead of for a foreach loop for every iteration of fetchRow(). Would you consider this to be an acceptable overhead? There will be times when over 1000 result are pulled from the database and in all likelihood by several users simultaneously. For the most part I will be caching these results but I'm not sure of the impact that foreach loop would have when repeated that number of times.


    Am I just being rather pessimistic?

  22. #22
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by me
    You can use data_seek alongside fetch_assoc().
    Never mind that is for a result instance.

  23. #23
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by oddz View Post
    You can use data_seek alongside fetch_assoc().
    i can use data_seek but i don't see any advantage in its use. fetch_assoc() is a method of the result object only.

    PHP Code:
        public function fetchRow()
        {    
            
    $this->_statement->data_seek($this->_index);
            
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_fieldRow;
        } 
    EDIT:
    Quote Originally Posted by oddz View Post
    Never mind that is for a result instance.
    Missed that post.

  24. #24
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,182
    Mentioned
    16 Post(s)
    Tagged
    4 Thread(s)
    Shot in the dark:

    PHP Code:
        private function _bindResult()
        {
            
    $this->_metaData $this->_statement->result_metadata();
            
            
    $values array_slice($this->_fieldRow,0);
            
            while (
    $field $this->_metaData->fetch_field()) {
            
                
    $this->_fieldParams[] = &$values[$field];
                
            }

            
    call_user_func_array(array($this->_statement'bind_result'), $this->_fieldParams);
            
            
    $this->_fieldRow $values;
        }

        public function 
    fetchRow()
        {
            if (
    $this->_index >= $this->numRows()) {
                return 
    false;
            }
            if (!
    $this->_statement->fetch()) {
                return 
    false;
            }
            
    $this->_index++;

            return  
    $this->_fieldRow
        } 

  25. #25
    SitePoint Zealot GOPalmer's Avatar
    Join Date
    Jan 2009
    Location
    Wiltshire, UK
    Posts
    125
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    thanks again oddz but i get exactly the same problem with that.


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
  •