PHP: Calling Methods on Non-Objects

PHP has subtly changed the wording of this error between various versions of the language, which can trip up your log aggregators when you upgrade so I thought I’d give a quick rundown of the changes around the “call to member function on non-object” error in PHP, up to and including PHP 7 which has an entirely new error handling approach.

As an example I’m using this piece of nonsense which just sets $a to be a number and then attempts to call a method on it:

<?php
require __DIR__ . "/../../vendor/autoload.php";

use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\RequestException;

class DocumentTest extends \PHPUnit\Framework\TestCase
{
    public function setUp() {
        // create the first request to check we can connect, can be added to
        // the mocks for any test that wants it
        $couchdb1 = '{"couchdb":"Welcome","version":"2.0.0","vendor":{"name":"The Apache Software Foundation"}}';
        $this->db_response = new Response(200, [], $couchdb1);

        // offer a use_response for when selecting this database
        $egdb1 = '{"db_name":"egdb","update_seq":"0-g1AAAABXeJzLYWBgYMpgTmEQTM4vTc5ISXLIyU9OzMnILy7JAUklMiTV____PyuRAY-iPBYgydAApP5D1GYBAJmvHGw","sizes":{"file":8488,"external":0,"active":0},"purge_seq":0,"other":{"data_size":0},"doc_del_count":0,"doc_count":0,"disk_size":8488,"disk_format_version":6,"data_size":0,"compact_running":false,"instance_start_time":"0"}';
        $this->use_response = new Response(200, [], $egdb1);

        $create = '{"ok":true,"id":"abcde12345","rev":"1-928ec193918889e122e7ad45cfd88e47"}';
        $this->create_response = new Response(201, [], $create);
        $fetch = '{"_id":"abcde12345","_rev":"1-928ec193918889e122e7ad45cfd88e47","noise":"howl"}';
        $this->fetch_response = new Response(200, [], $fetch);
    }

    /**
     * @expectedException \PHPCouchDB\Exception\DocumentConflictException
     */
    public function testDeleteConflict() {
        $delete = '{"error":"conflict","reason":"Document update conflict."}';
        $delete_response = new Response(409, [], $delete);

        $mock = new MockHandler([ $this->db_response, $this->use_response, $this->create_response, $this->fetch_response, $delete_response ]);
        $handler = HandlerStack::create($mock);
        $client = new Client(['handler' => $handler]);

        // userland code starts
        $server = new \PHPCouchDB\Server(["client" => $client]);
        $database = $server->useDB(["name" => "egdb"]);
        $doc = $database->create(["noise" => "howl", "id" => "abcde12345"]);

        $result = $doc->delete();
    }
}

This doesn’t work but the exact output varies between versions of PHP.

In PHP 5.5 (and maybe earlier, I don’t seem to have any of the dead versions compiled on this machine for some reason), the error message reads like this:

Fatal error: Call to a member function grow() on a non-object in /home/lorna/.../method_non_object.php on line 7

So far, so familiar.

In PHP 5.6 the error message got a bit more specific and tells us what kind of a non-object we’re dealing with:

PHP Fatal error: Call to a member function grow() on integer in /home/lorna/.../method_non_object.php on line 7

However in PHP 7, everything changes. Look at the error message output by the exact same sample code:

Fatal error: Uncaught Error: Call to a member function grow() on integer in /home/lorna/.../method_non_object.php:7

This message looks completely different because PHP 7 has a whole new way of handling errors. Not every part of PHP has switched over to the new way but it’s both excellent and quite a big change. The clue in the message which starts with the word “Uncaught”. Usually we’d expect the next word to be “Exception” but in PHP 7 there is a new Error object, which can be intercepted using the catch construct that we’re already familiar with.

I’ll write more about the errors in PHP 7 in a separate post but in the meantime you can read more about them in the manual (this might be my favourite manual page URL): http://php.net/error

2 thoughts on “PHP: Calling Methods on Non-Objects

  1. Pingback: PHP Annotated Monthly – November 2015 | JetBrains PhpStorm Blog

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.