0

I use the transient this way (simple Example):

function my_url_cache( $url ) 
{
   $transient_id = hash( "crc32", $url );
   $content = get_transient( 'my_url_cache_' . $transient_id );
   set_transient( 'my_url_cache_' . $transient_id, $content, 60 * 60 * 24 );
   set_transient( 'my_url_cache_backup_' . $transient_id, $content, 0 ); 
}

Together with a plugin from my company they get this error, when they want to refresh their cache:

Call to a member function get() on a non-object in /wordpress/wp-includes/cache.php on line 123

Without my plugin they have no problems

/wordpress/wp-includes/cache.php on line 123:

/**
 * Retrieves the cache contents from the cache by key and group.
 *
 * @since 2.0.0
 *
 * @see WP_Object_Cache::get()
 * @global WP_Object_Cache $wp_object_cache Object cache global instance.
 *
 * @param int|string  $key    The key under which the cache contents are stored.
 * @param string      $group  Optional. Where the cache contents are grouped. Default empty.
 * @param bool        $force  Optional. Whether to force an update of the local cache from the persistent
 *                            cache. Default false.
 * @param bool        $found  Optional. Whether the key was found in the cache. Disambiguates a return of false,
 *                            a storable value. Passed by reference. Default null.
 * @return bool|mixed False on failure to retrieve contents or the cache
 *                    contents on success
 */
    function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
        global $wp_object_cache;

        return $wp_object_cache->get( $key, $group, $force, $found ); // Line 123
    }

On my Testserver I cannot reproduce this error.

They don't use a different Caching system.

The $wp_object_cache seems not to be an object. I don't know if for my plugin or their plugin or both.

Do I have to use a special hook in Wordpress, before I can use the get_ and set_transient functions? I use my cache function inside this hook only:

add_shortcode( 'feedimport', array( $this, "shortcode_feedimport" ) );

UPDATE:

The other plugin uses the wp_schedule_event:

private static function cron_schedule_event_setup() {
    wp_clear_scheduled_hook(self::cron_hook);
    wp_schedule_event(time(), self::$options['schedule_event'], self::cron_hook);
}

And store their data in a database table. They don't use the get_ set_transient functions. :(

I realy don't know how my plugin can affect their plugin. Full Code of their plugin: link

Update 2 - Solved:

public function __destruct() {
    $this->save_log();
}

This code starts a function which uses the wordpress caching system.

Changing to this:

add_action('shutdown', array($this, "save_log"));

Solved the Problem. I never use Wordpress Functions again in a Destructor.

5
  • How/where do you call my_url_cache()?
    – kero
    Oct 16 '17 at 13:25
  • Inside the hook plugins_loaded I add a shortcode and inside this shortcode I call my_url_cache(). Oct 16 '17 at 13:33
  • add_action( 'plugins_loaded', array( 'my_plugin_class', 'instance' ) ); Oct 16 '17 at 13:34
  • Full Code: link Oct 16 '17 at 13:55
  • After short read of your code, you get the transient on the hook wp_ajax_* that have not the global, not a cache object. You should get the transient before you fire the ajax request.
    – bueltge
    Oct 16 '17 at 15:54
0

Indeed, you have to be careful when using __destruct.

This is a special function that fires when the object is about to be destroyed. When PHP calls exit (as wp_send_json() does), we do not control in what order PHP will destroy the objects.

So __destruct is very dangerous when it relies on other classes. I've seen this causing fatals especially on PHP 5.6, which leads to errors like this:

/**
 * Job destructor
 */
public function __destruct()
{
    $this->logger->commit();
}

Fatal error: Uncaught Error: Call to a member function commit() on null

The Solution

Instead of:

$job = new Job;
wp_send_json($job->start());

Do:

wp_send_json((new Job)->start());

Which is the same as:

$job = new Job;

$results = $job->start();

// Trigger __destruct while we are on a known state
unset($job);

wp_send_json($results);

You have to do this when the PHP process is going to be interrupted by an exit or a die.

wp_send_json() is the most notable example, as we use it a lot and it calls exit right after echoing the JSON string. But this could apply to other functions, like wp_die(), exit, die, etc.

Bottom line, just make sure that a function that uses __destruct is destroyed if the PHP process is going to be interrupted, otherwise, this could cause issues.

Proof of concept: https://3v4l.org/GBBIV

__destruct running on multiple PHP versions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.