Asked  1 Year ago    Answers:  5   Viewed   16 times

Getting a very strange error here, I am writing a flatfile database class and this was all working fine until I refreshed and now I am constantly getting this message:

Fatal error: Call to a member function name() on a non-object in /home/reithg/public_html/test/engine/class.database.php on line 50

I am calling the Class as follows:

<?php
ini_set('display_errors', '1');

require('engine/class.database.php');

$config = new Config("lessons", array('first', 'second', 'third', 'fourth'), "data/");
$db = new Database($config, true);

print("Querying DB for 'theta' no exclusions: <br />");
print_r($db->query('theta', NULL, NULL));

print("<p /> Querying DB for 'theta' in column 'second': <br />");
print_r($db->query('theta', 'second', NULL));

print("<p /> Querying DB for first two rows: <br />");
print_r($db->getRows(2));

print("<p /> Querying DB for last three rows: <br />");
print_r($db->getRows(3, true));

print("<p /> Cleaning data for safe DB input: <br />");
$testInput = array('escape|these||delimiters','andthese\slashes','andthesenulls',"don't, forget quotes");
print("input: ");
print_r($testInput);
echo("<br />output: ");
print($db->addRow($testInput));
?>

Here is my class.database.php

<?php
require('class.config.php');
require('class.column.php');

    class Database {
        private
            $_config,
            $_pointer;

        public function __construct(Config $config)  {
            $this->_config = $config;
            return true;
        }

        private function connect($method) {
            if (!($this->_pointer = @fopen($this->_config->db(), $method)))
            echo("Unable to connect to database");
        }

        private function disconnect() {
            fclose($this->_pointer);
        }

        private function lock($method) {
            if(flock($this->_pointer, $method))
                return true;
            return false;
        }

        private function unlock() {
            flock($this->_pointer, LOCK_UN);
        }

        private function cleanInput($input) {   
            $data = array_map(array($this, 'escapeData'), $input);
            $output = implode($this->_config->delimiter(), $data)."rn";
            return $output;
        }

        private function escapeData($data) 
        {
            $search = array('\', '"', "'", '\0', 'n', $this->_config->delimiter());
            $replace = array('\\', '"', "'", '\0', '\n', '\'.$this->_config->delimiter());
            $output = str_replace(array_unique($search), array_unique($replace), $data);
            return $output;
        }

        private function formatRow($data) {
            foreach($data as $key => $value) {
                $row[$this->_config->columns($key, "position")->name()] = $value;
            }
            return $row;
        }

        public function dumpToArray() {
            $arrayDump;
            foreach(file($this->_config->db(), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $row => $content)
                $arrayDump[$row] = formatRow(explode($this->_config->delimiter(),$content));
            return $arrayDump;
        }

        public function addRow(array $data) {
            $this->connect('ab');
            if($this->lock(LOCK_EX)) {
                // fwrite($this->_pointer, $this->cleanInput($data));
                echo($this->cleanInput($data));
                $this->unlock();
                $this->disconnect();
                return true;
            } else {
                $this->disconnect();
                return false;
            }
        }

        public function query($value, $column = NULL, $limit = NULL) {
            $this->connect('rb');
            $results = array();
            while ((is_null($limit) || (count($results) < $limit)) && !feof($this->_pointer)) {
                $data = explode($this->_config->delimiter(), fgets($this->_pointer, 1024));
                if(!is_null($column)) {
                    if ($data[$this->_config->columns($column, "string")->index()] == $value)
                        array_push($results, $this->formatRow($data));
                } else {
                    if (in_array($value, $data))
                        array_push($results, $this->formatRow($data));
                }
            }
            $this->disconnect();
            switch (count($results)) {
                case 0;
                    return false;
                case 1;
                    return $results[0];
                default;
                    return $results;
            }
        }

        public function getRows($limit = 1, $reverse = false) {
            $this->connect('rb');
            $offset = 0;
            $results = array();
            if ($reverse) {
                while(count($results) < $limit && fseek($this->_pointer, $offset, SEEK_END) >= 0) {
                    $char = fgetc($this->_pointer);
                    if($char == "n" || $char == "r"){
                        $offset --;
                        $data = explode($this->_config->delimiter(), fgets($this->_pointer, 1024));
                        array_push($results, $this->formatRow($data));
                    }
                    $offset--;
                }
                $results = array_reverse($results);
            } else {
                while ((($limit === NULL) || (count($results) < $limit)) && !feof($this->_pointer)) {
                    $data = explode($this->_config->delimiter(), fgets($this->_pointer, 1024));
                    array_push($results, $this->formatRow($data));
                }
            }
            $this->disconnect();
            return $results;
        }
    }
?>

class.config.php

<?php
    class Config {
        private
            $_db,
            $_file,
            $_columns = array(),
            $_directory,
            $_delimiter;

        public function __construct($file, array $columns, $directory = NULL, $delimiter = "|")  {
            $this->_db = $directory.$file.".db";
            $this->defineColumns($columns);
            $this->_directory = $directory;
            $this->_delimiter = $delimiter;
        } 

        public function db() {
            return $this->_db;
        }

        public function delimiter() {
            return $this->_delimiter;
        }       

        private function defineColumns($constants) {
            for ($i=0;$i<count($constants);$i++) {
                if(in_array($constants[$i], $this->_columns))
                    die("Column names must be unique");
                $column = new Column($constants[$i], $i);
                $this->_columns[$column->name()] = $column;
            }
        }

        public function columns($index, $search = "string") {
            switch ($search) {
                case "string";
                    return $this->_columns[$index];
                    break;
                case "position";
                    $keys = array_keys($this->_columns);
                    return $this->_columns[$keys[$index]];
                    break;
                default;
                    return false;
            }   
        }
    }
?>

class.column.php

<?php
    class Column { 
        const
            ALL = "0",
            STRING = "1",
            NUMBER = "2",
            INT = "3",
            AUTO_INCREMENT = "4",
            CURRENT_TIME = "5";

        private
            $_type = ALL,
            $_name,
            $_index,
            $_maxChars = "256";

        public function __construct($name, $index, $type = NULL, $maxChars = NULL)  {
            $this->_name = $name;
            $this->_index = $index;
            if(!is_null($type))
                setDataType($type);
            if(!is_null($maxChars))
                setMaxChars($maxChars);
            return $this;
        }

        public function setDataType($type) {
            switch ($type) {
                case ALL;
                case STRING;
                case NUMBER;
                case INT;
                case AUTO_INCREMENT;
                case CURRENT_TIME;
                    $this->_type = $type;
                    break;
                default;
                    return false;
            }
        }

        public function auditData($data) {
            switch ($this->_type) {
                case ALL;
                    $output = $data;
                    break;
                case STRING;
                    $output = (string) $data;
                    break;
                case NUMBER;
                    $output = (float) $data;
                    break;
                case INT;
                    $output = (int) $data;
                    break;
                case AUTO_INCREMENT;
                    $output = (int) $data;
                    break;
                case CURRENT_TIME;
                    $output = time();
                    break;
                default;
                    return false;
            }
            return $output;
        }

        public function setMaxChars($maxChars) {
            if(is_int($maxChars)) {
                $this->_maxChars = $maxChars;
            }
        }

        public function name() {
            return $this->_name;
        }

        public function index() {
            return $this->_index;
        }
    }
?>

I know it's a lot of code but I can't work out why this is happening all of a sudden, literally in one refresh without any change to code. Even if I backtrace to earlier versions that also worked this is happening.

When I attempt to do:

print($this->_config->columns($key, "position"));

It returns:

Catchable fatal error: Object of class Column could not be converted to string in /home/reithg/public_html/test/engine/class.database.php *on line 50*

Which shows that I am performing name() on a member of class Column which has a public method called name()

When I do:

print($this->_config->columns($key, "position")->name());

it returns (one word per time as it is in a foreach loop);

first second third fourth first second third fourth

So it is clearly working 1 line before it.

 Answers

3

The answer was due to hidden characters located in the lessons.db file.

The error shown had nothing to do with this and I would like to thank everyone who took the time to give their two pence.

Thursday, April 1, 2021
 
FWH
 
FWH
4

Based on the information you’re providing the best and most practical solution is to simply do a check to see if $html and $content is empty or not.

9 times out of 10 when you get a “Call to a member function [whatever the function is] on a non-object” that basically means the object just doesn’t exist. Meaning the variable is empty. Here is your code reworked:

$url = "static/" . $cat_map[$cat]['url'];
if (!empty($url)) {
  $html = file_get_html($url);
  if (!empty($html)) {
    $content = $html->find('div#event-pane > div#e' . $event_id, 0);
    if (!empty($content)) {
      $content->find('a.openevent', 0)->innertext = '';
      $content->find('h3.lshtitle', 0)->onclick = '';
      $content->find('h3.lshtitle', 0)->tag = 'div';
      $content->find('div.lshtitle', 0)->class = 'ttl';
    }
  }
}

Also, I added a check to see if the $url is empty as well.

Saturday, May 29, 2021
 
xrock
 
5

With this, you can define your own continuation function that will take over in case of a fatal error. This uses register_shutdown_function() to intercept the fatal error.

Usage:

function my_continuation_func($filename, $arg2) {
    // On fatal error during include, continue script execution from here.
    // When this function ends, or if another fatal error occurs,
    // the execution will stop.
}

include_try('my_continuation_func', array($filename, $arg2));
$data = include($filename);
$error = include_catch();

If a fatal error occurs (like a parse error), script execution will continue from my_continuation_func(). Otherwise, include_catch() returns true if there was an error during parsing.

Any output (like echo 'something';) from the include() is treated as an error. Unless you enabled output by passing true as the third argument to include_try().

This code automatically takes care of possible working directory changes in the shutdown function.

You can use this for any number of includes, but the second fatal error that occurs cannot be intercepted: the execution will stop.

Functions to be included:

function include_try($cont_func, $cont_param_arr, $output = false) {
    // Setup shutdown function:
    static $run = 0;
    if($run++ === 0) register_shutdown_function('include_shutdown_handler');

    // If output is not allowed, capture it:
    if(!$output) ob_start();
    // Reset error_get_last():
    @user_error('error_get_last mark');
    // Enable shutdown handler and store parameters:
    $params = array($cont_func, $cont_param_arr, $output, getcwd())
    $GLOBALS['_include_shutdown_handler'] = $params;
}

function include_catch() {
    $error_get_last = error_get_last();
    $output = $GLOBALS['_include_shutdown_handler'][2];
    // Disable shutdown handler:
    $GLOBALS['_include_shutdown_handler'] = NULL;
    // Check unauthorized outputs or if an error occured:
    return ($output ? false : ob_get_clean() !== '')
        || $error_get_last['message'] !== 'error_get_last mark';
}

function include_shutdown_handler() {
    $func = $GLOBALS['_include_shutdown_handler'];
    if($func !== NULL) {
        // Cleanup:
        include_catch();
        // Fix potentially wrong working directory:
        chdir($func[3]);
        // Call continuation function:
        call_user_func_array($func[0], $func[1]);
    }
}
Saturday, May 29, 2021
 
hnkk
 
4

It means that $objPage is not an instance of an object. Can we see the code you used to initialize the variable?

As you expect a specific object type, you can also make use of PHPs type-hinting featureDocs to get the error when your logic is violated:

function page_properties(PageAtrributes $objPortal) {    
    ...
    $objPage->set_page_title($myrow['title']);
}

This function will only accept PageAtrributes for the first parameter.

Tuesday, June 1, 2021
 
Jeff
 
2

The problem isn't with the $name variable but rather with the $_engine variable. It's currently empty. You need to verify that the path specification to Smarty.class.php is correct.

You might try this to begin your debugging:

$this->_engine = new Smarty();
print_r($this->_engine);

If it turns out that $_engine is correct at that stage then verify that it is still correctly populated within the render() function.

Wednesday, June 9, 2021
 
LaKaede
 
4

You access the property in the wrong way. With the $this->$my_value = .. syntax, you set the property with the name of the value in $my_value. What you want is $this->my_value = ..

$var = "my_value";
$this->$var = "test";

is the same as

$this->my_value = "test";

To fix a few things from your example, the code below is a better aproach

class my_class {

    public  $my_value = array();

    function __construct ($value) {
        $this->my_value[] = $value;
    }

    function set_value ($value) {
        if (!is_array($value)) {
            throw new Exception("Illegal argument");
        }

        $this->my_value = $value;
    }

    function add_value($value) {
        $this->my_value = $value;
    }
}

$a = new my_class ('a');
$a->my_value[] = 'b';
$a->add_value('c');
$a->set_value(array('d'));

This ensures, that my_value won't change it's type to string or something else when you call set_value. But you can still set the value of my_value direct, because it's public. The final step is, to make my_value private and only access my_value over getter/setter methods

Wednesday, June 9, 2021
 
muaaz
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share