9

We have very strange errors occasionally popping up in our php logs: Trying to get property of non-object.

This exact error seems to be caused by the access to the member $shortName in the following if statement:

class MyLocaleWrapper extends SomeOtherClass {
    …
    protected static $system = NULL;
    public static function getSystemLocale() {
        if (self::$system === NULL) {
            self::$system = new self();
            debug(self::$system);
            self::$system->rfcName = SYSTEM_LOCALE_RFCNAME;
            self::$system->shortName = strtolower(Locale::getRegion(self::$system->rfcName));
            if (self::$system->shortName == '') {
                self::$system->shortName = strtolower(self::$system->rfcName);
            }
            …

# in another file:
class SomeOtherClass {
    …
    public function __construct() {
        # Some documentation about features that have been
        # removed from the constructor, but no real code in here.
        return NULL;
    }
    …

# in yet another file:
MyLocaleWrapper::getSystemLocale();

if I dump self::$system into a log file, I see that it is NULL - right after being constructed with the keyword new.

The most interesting part is that this file is included in each and every request to our page, so it gets executed ~ 10 times per second. But occasionally it just fails without anyone touching the code (or even the server).

Has anyone else ever experienced such behavior in PHP?

16
  • 2
    is there anything inside the code that can reset the static instance? Commented Oct 21, 2010 at 16:47
  • Hm...why are you creating a new instance of the class from within the class? I'm probably wrong, but wouldn't it make more sense to create a single instance when you initially call it, and refer to it from within with the $this keyword? Commented Oct 21, 2010 at 16:47
  • @Gordon: The code I pasted is complete, I haven't left anything out - but I have hard times believing this myself. Commented Oct 22, 2010 at 7:43
  • @treeface This is not a singleton, but rather a built-in factory. There can be multiple locales in the application - but one of them is the system locale. Commented Oct 22, 2010 at 7:45
  • @soulmerge I guess you will have to use XDebug to get more information about what happens at runtime. Commented Oct 22, 2010 at 7:55

6 Answers 6

1

Thanks for all the updates. (see extensive comments above on original post).

Unfortunately, I'm as stumped as you are -- everything looks fine with that code.

Either

  1. you've found some rather obscure bug in php, or...
  2. the symptoms are tricking you into thinking the problem is in one place, when it's actually somewhere else, or...
  3. we're all missing something in that code that should be obvious to a bunch of seasoned php developers. ;-)

If it were my production system to deal with, I'd probably comment out the return NULL in the constructor, and let it run in production for a while. That return shouldn't cause any problems, but it's the only strange thing I can see here.

Sorry I can't help more than that. Please come back and let us know if you figure it out.

Sign up to request clarification or add additional context in comments.

Comments

1

We finally found out we were running into php bug #50027. After setting the php.ini-variable zend.enable_gc to false, the error vanished.

Comments

0

Try the singleton approach:

class MyLocaleWrapper {
    …
    private static $system = NULL;//set it to private, and instead of accessing it as $this->system, access it with self::getInstance() or parent::getInstance() if your trying to get the parent instance
    public static function getInstance() {
        if (!(self::$system instanceof self)){
            self::$system = new self();
        }
        return self::$system;
    }
    final private function __construct() { }// Do not allow an explicit call of the constructor: $v = new Singleton();
    final private function __clone() { }// Do not allow the clone operation: $x = clone $v;
    public static function getSystemLocale() {
        $self = self::getInstance();
        log($self);//dump the value into a file with you function
…

and see what the value of $self is

Your problem seems to spawn from something overwriting or just because your not setting the $system variable

with the singleton approach you ensure that the instance has only been set once and that nothing is overwriting it.

p.s. what does the file actually do?

4 Comments

I can hardly change the production server like that. But I have print_r()ed the value into a file and $this was NULL.
usually you have a development server and a production server, but I have experienced working with production code directly as well, so ill edit my answer.
@soulmerge: you said you have "print_r()ed the value" of $this. There are 2 problems with that statement: 1. you're in a static function, so $this will never exist; 2. print_r(NULL) prints nothing -- not "NULL". var_dump(NULL) would print "NULL". I assume you meant something like: "I have var_dump()ed the value of self::$system?
@Lee: 1.) Sorry, I meant that $system was NULL 2.) I was using a custom debugging function that verified that the value was NULL (I'm using the function for several years now, I highly doubt it has a bug like that)
0

What is this line: self::$system->shortName = strtolower(Locale::getRegion($rfcName));? Where does the $rfcName come from? If it's not defined before you trying to use it, that would cause an error, causing the rest of the code to fail, giving you the problem you describing.

Since I don't see your entire class, I don't have all the information to answer the question, so this is just a guess

Comments

0

This will print the object once

class MyLocaleWrapper extends SomeOtherClass {

    protected static $system = NULL;
    public static function getSystemLocale() {
        if (self::$system === NULL) {
            self::$system = new MyLocaleWrapper();

            self::$system->rfcName = 'test';
            self::$system->shortName = strtolower('test');
            if (self::$system->shortName == '') {
                self::$system->shortName = strtolower('test');
            }
                print_r(self::$system);

        }
        return self::$system;
    }
}

# in another file:
class SomeOtherClass {

    public function __construct() {
        # Some documentation about features that have been
        # removed from the constructor, but no real code in here.
        return NULL;
    }
}

# in yet another file:
$l = MyLocaleWrapper::getSystemLocale();
$l = MyLocaleWrapper::getSystemLocale();

Comments

-1

Not sure if you figured this out but I would try assigning the new object directly to a variable, then assign it to self::$system later on. Something like the code below may help.

$newSystem = new self();
$newSystem->rfcName = SYSTEM_LOCALE_RFCNAME;
$newSystem->shortName = strtolower(Locale::getRegion($rfcName));
....
self::$system = $newSystem

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.