[web] [PHP] Damn, I don't get it - aka 'Call to a member function on a non-object'

Started by
6 comments, last by konForce 16 years, 11 months ago
You guess it, I have a problem with my PHP code.

The background...

First, let's give you some information. I have a bunch of files: * index.php require lib/prepend.php * lib/prepend.php requires lib/connection.php (connection to a mysql db), then requires lib/application_settings.php (which requires lib/app_settings_recordset.php) and instantiate the application_settings class, then requires {theme_dir}/template.php. The application_settings class issue a SQL query using the connection object, and stores the result in a app_settings_recordset object. The code to issue the request and create the object is there:
function select($query, $classname)
{
  if ($classname == "" || !class_exists($classname)) {
    return false;
  }
  if ($this->connection_link) {
    $this->request_count += 1;
    $result = @mysql_unbuffered_query($query, $this->connection_link);

    if ($result) {
      $record = array();
      $index = 0;
      while ($row = @mysql_fetch_row($result)) {
        for($j=0; $j<count($row); $j++) {
          $record[$index][strtolower(@mysql_field_name($result, $j))] = $row[$j];
        }
        ++$index;
      }
      return new $classname($record);
    }
  }
  $this->retrieve_error();
  return false;
}

The function si called with:
$this->records = &$this->connection->select(
  "SELECT * FROM ".DB_PREFIX."app_settings", 
  'app_settings_recordset');
The app_settings_recordset exists and there is no typo here. The application settings object is created using:
$app_settings = &new application_settings($connection);
All of this seems to work, because I'm able to use the application settings to get the theme directory in order to include the template.php file. The first php statement in this template.php file is a quite simple:
<? $app_settings->print_language(); ?>
. And then things tend to go uterly wrong. For this line, I get a superb Call to a member function on a non-object, which should mean that $app_settings is not an object (a var_dump shows me that it's not even a variable). Which is plain strange because I just used it successfully to retrieve the theme directory. Here is the code of application_settings.php:

<?

require dirname(__FILE__) . '/app_settings_recordset.php';

class application_settings
{
    var $connection;
    var $records;
    var $app_directory;

    function application_settings(&$con, $app_directory)
    {
        $this->connection = &$con;
        $this->app_directory = $app_directory;
        $this->load_settings();
    }
    
    function load_settings()
    {
        $this->records = &$this->connection->select("SELECT * FROM ".S4_DB_PREFIX."app_settings", 'app_settings_recordset');
    }
    
    function get_images_directory()
    {
        return $this->app_directory . '/images';
    }
    
    function get_theme_directory()
    {
        if ($this->records) {
            return $this->app_directory . '/themes/'.$this->records->get('theme');
        }
        return $this->app_directory . '/themes/default';
    }
    
    
    function get_language()
    {
        if ($this->records) {
            $records = &$this->records;
            return $records->get('language'); 
        }
        return 'fr';
    }
    
    function get_base_url()
    {
        if ($this->records) {
            $records = &$this->records;
            return $records->get('base_url');
            // return 'http://localhost/eras-of-enk';
        }
        return '';
        
        //return 'http://localhost/eras-of-enk';
    }

    function get_encoding()
    {
        if ($this->records) {
            return $this->records->get('encoding'); 
        }
        return '';
    }
    
    function print_language() { echo $this->get_language(); }
    function print_encoding() { echo $this->get_encoding(); }
    function print_images_directory() { echo $this->get_images_directory(); }
    function print_theme_directory() { echo $this->get_theme_directory(); }
    function print_base_url() { echo $this->get_base_url(); }
}

?>

And the code for app_settings_recordset.php:

<?

class app_settings_recordset
{
    var $records = array();
    
    function app_settings_recordset($raw_records)
    {
        foreach ($raw_records as $index=>$rec) {
            if (is_array($rec)) {
            	$n = "";
                $v = "";
                foreach($rec as $key=>$value) {
                    if ($key == "name") {
                        $n = strtolower($value);
                    } else if ($key == "value") {
                        $v = $value;
                    }
                }
                if ($n != "" && $v != "") {
                    $this->records[$n] = $v;
                }
            }
        }
    }
    
    function get($name)
    {
        echo 'app_settings_recordset::get('.$name.')<br>';
        $lowername = strtolower($name);
        if (array_key_exists($lowername, $this->records)) {
            return $this->records[$lowername];
        }
        return '';
    }
    
    function is_empty()
    {
        return count($this->records) == 0;
    }
}

?>


The beginning of template.php is

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
  xml:lang="<? $app_settings->print_language(); ?>" 
  lang="<? $app_settings->print_language(); ?>">
<head>
  <meta http-equiv="Content-Type" 
    content="text/html; charset=<? $app_settings->print_encoding(); ?>" />
  <meta name="MSSmartTagsPreventParsing" content="TRUE" />

  <link rel="stylesheet" 
    type="text/css" 
    href="<? $app_settings->print_theme_directory(); ?>/style.css"
    media="screen" />
</head>


Now, it's not the weirdest thing. If I change application_settings::print_base_url() (and the other print functions, excepted the language and encoding ones) to:
    function print_base_url()
    {
        return 'http://localhost'; // or the corresponding string
    }
Then, suddenly, everything works as expected... And that's where I'm totally lost.

... and then, the question

Do you have any clue of what's happening there, and how I can overcome this stupid situation? I really need to find a solution to this situation, as I'm, well, blocked by that (well, in fact I should be able to use hard-coded strings, but that doesn't explain me what's wrong, and it will not correct the problem in the end). Best regards, and thanks for your help, [Edited by - Emmanuel Deloget on May 25, 2007 8:02:25 AM]
Advertisement
Is the instance global or local?
I am so stupid that I don't even understand how I failed to see that before I wrote the message before. I guess that writing the message made me understood something about my own code....

I have two different kind of path: filesystem paths, which allow me to find stuff in the server, and url, which allow a browser to find stuff on the server.

I decided to mix both, resulting in a royal mess. And of course, some failure here and there.

Changing the print_xxx() function to print urls and the get_xxx_directory() function to return filesystem path + adding some get_xxx_url() functions helped me to sort out the issue.

God, I'm so stupid...

Sorry for having stolen your time [embarrass]
Quote:Original post by ToohrVyk
Is the instance global or local?


It's a global.

I edited the OP becauseI did some mistakes in it - in the problem description.

The main difference between the two settings was expressed in a single line:
require $app_settings->get_theme_directory() . '/template.php' had a very different behavior:

* in the working version, $app_settings->get_theme_directory() is 'd:\....\www\lib/..'
* in the non-working version, it's 'http://localhost'

I guess I have a better understanding of the problem now [smile]

Edit: no, I'm not drunk... I just don't write correctly.

[Edited by - Emmanuel Deloget on May 25, 2007 8:16:19 AM]
Quote:Original post by Emmanuel Deloget
The application settings object is created using:
$app_settings = &new application_settings($connection);


It's been a while since I've worked with PHP but what does & do when used on the new operator? Also, we'll need to know what version of PHP you're using. It had a major object overhaul in PHP4 --> PHP5.

Edit: So you fixed it?
Quote:Original post by tstrimp
Quote:Original post by Emmanuel Deloget
The application settings object is created using:
$app_settings = &new application_settings($connection);


It's been a while since I've worked with PHP but what does & do when used on the new operator? Also, we'll need to know what version of PHP you're using. It had a major object overhaul in PHP4 --> PHP5.

PHP4. The & is the 'consider this to be a reference' operator. I don't fully understand how PHP works, so I won't explain you the difference between a reference and a normal variable :)

Quote:Edit: So you fixed it?


Yep.
Quote:Original post by Emmanuel Deloget
PHP4. The & is the 'consider this to be a reference' operator. I don't fully understand how PHP works, so I won't explain you the difference between a reference and a normal variable :)


I understood it was a reference, I've just never seen it used with the new operator like that.
In PHP 5 the & does nothing when dealing with objects.

<?php  class Foo  {    public $value;  }  $foo = new Foo;  $bar = $foo;  $bar->value = "Hello, World!";  echo $foo->value."\n";?>


The text "Hello, World!" will be displayed.

If you want a copy, you have to ask for one via the clone keyword. ($bar = clone $foo;)

In PHP 4, the default behavior of "new" was to not return a reference. It was a silly design decision, so people got around it by using the "=& new" syntax.

So if you're writing code that is meant to run on PHP 4, then you should use the reference operator with new. But if your application is PHP 5 only then you can just forget about it.

This topic is closed to new replies.

Advertisement