PHP фатальная ошибка в cache.php на строке 123 $wp_object_cache — не объект.

Вопрос или проблема

Я использую транзиент таким образом (простой пример):

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 ); 
}

Вместе с плагином моей компании у них возникает эта ошибка, когда они хотят обновить свой кэш:

Вызов метода get() для не объекта в
/wordpress/wp-includes/cache.php на строке 123

Без моего плагина у них нет проблем

/wordpress/wp-includes/cache.php на строке 123:

/**
 * Извлекает содержимое кэша по ключу и группе.
 *
 * @since 2.0.0
 *
 * @see WP_Object_Cache::get()
 * @global WP_Object_Cache $wp_object_cache Глобальный экземпляр кэша объектов.
 *
 * @param int|string  $key    Ключ, под которым хранится содержимое кэша.
 * @param string      $group  Необязательно. Где содержимое кэша сгруппировано. По умолчанию пусто.
 * @param bool        $force  Необязательно. Обновлять ли локальный кэш из постоянного кэша.
 *                            По умолчанию false.
 * @param bool        $found  Необязательно. Найден ли ключ в кэше. Различает возвращаемое значение false,
 *                            хранимое значение. Передается по ссылке. По умолчанию null.
 * @return bool|mixed False в случае неудачи получения содержимого или содержимое кэша
 *                    в случае успеха
 */
    function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
        global $wp_object_cache;

        return $wp_object_cache->get( $key, $group, $force, $found ); // Строка 123
    }

На моем тестовом сервере я не могу воспроизвести эту ошибку.

Они не используют другую систему кэширования.

Похоже, что $wp_object_cache не является объектом. Я не знаю, связано ли это с моим плагином, их плагином или обоими.

Должен ли я использовать специальный хуки в WordPress, прежде чем я смогу использовать функции get_ и set_transient? Я использую свою функцию кэширования только внутри этого хуки:

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

ОБНОВЛЕНИЕ:

Другой плагин использует 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);
}

И сохраняют свои данные в таблице базы данных. Они не используют функции get_ set_transient. 🙁

Я действительно не знаю, как мой плагин может повлиять на их плагин. Полный код их плагина: ссылка

Обновление 2 – Решено:

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

Этот код запускает функцию, которая использует систему кэширования WordPress.

Изменив на это:

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

Проблема была решена. Я больше никогда не использую функции WordPress в деструкторе.

Действительно, вы должны быть осторожны при использовании __destruct.

Это специальная функция, которая срабатывает, когда объект собирается быть уничтожен. Когда PHP вызывает exit (как делает wp_send_json()), мы не контролируем, в каком порядке PHP будет уничтожать объекты.

Таким образом, __destruct очень опасен, когда он зависит от других классов. Я видел, как это вызывает фатальные ошибки, особенно в PHP 5.6, что приводит к ошибкам, таким как:

/**
 * Деструктор задания
 */
public function __destruct()
{
    $this->logger->commit();
}

Фатальная ошибка: Нервный сбой: Вызов метода commit() для null

Решение

Вместо:

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

Делайте:

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

Что аналогично:

$job = new Job;

$results = $job->start();

// Запустите __destruct, пока мы находимся в известном состоянии
unset($job);

wp_send_json($results);

Вы должны сделать это, когда процесс PHP будет прерван с помощью exit или die.

wp_send_json() является наиболее заметным примером, поскольку мы используем его часто и он вызывает exit сразу после вывода строки JSON. Но это также может применяться к другим функциям, таким как wp_die(), exit, die и т.д.

В конечном счете, просто убедитесь, что функция, которая использует __destruct, уничтожается, если процесс PHP будет прерван, иначе это может вызвать проблемы.

Доказательство концепции: https://3v4l.org/GBBIV

__destruct работает на нескольких версиях PHP

Ответ или решение

Ошибка PHP Fatal Error: $wp_object_cache is non-object

Ошибка, которую вы наблюдаете, указывает на то, что переменная $wp_object_cache не является объектом в момент ее вызова в функции wp_cache_get. Ваша проблема возникла на сервере клиента при использовании вашего плагина, в то время как тестовый сервер не проявил аналогичных проблем. Давайте подробно рассмотрим возможные причины и решения этой ошибки.

1. Понимание проблемы

При вызове функции wp_cache_get (где возникает ошибка на строке 123 в файле cache.php) происходит попытка доступа к методу get() объекта $wp_object_cache. Если переменная не инициализирована или не содержит корректный объект, система выдаст ошибку «Fatal Error».

2. Что может вызвать данную ошибку

  • Неинициализированная переменная: На вашем тестовом сервере объект кэша мог быть инициализирован, тогда как на клиентском сервере этого не произошло. Обычно $wp_object_cache инициализируется при загрузке ядра WordPress, и если ваш плагин мешает этому процессу (например, в __destruct методе или при неправильных вызовах), это может привести к проблемам.

  • Использование функции в неправильный момент: Ваша функция кэширования должна вызываться в правильный момент жизненного цикла WordPress. Если вы вызываете get_transient или set_transient слишком рано (например, до полной инициализации WordPress), это может вызвать ошибки.

3. Как решить проблему

Судя по вашему обновлению, ошибка была вызвана использованием функций WordPress в методе __destruct. Это является плохой практикой, поскольку функции WordPress могут быть заблокированы или не доступны в момент уничтожения объекта. Вместо этого рекомендуем использовать add_action с хуком shutdown, чтобы убедиться, что ваши функции вызываются в правильное время.

Изменение вашего кода:

Вместо:

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

Используйте:

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

Это гарантирует, что функция будет выполнена на этапе завершения выполнения всех действий, при этом не нарушая жизненный цикл объектов.

4. Рекомендации по разработке

  • Избегайте __destruct для функций WordPress: Используйте хуки и действия WordPress для выполнения кода, связанным с состоянием или событиями в WordPress.

  • Логирование ошибок: Включите логирование ошибок в wp-config.php для более детального анализа возможных причин.

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
  • Проверяйте наличие объекта: Перед использованием методов объекта, всегда проверяйте, является ли он инициализированным. Например:
if (is_object($wp_object_cache)) {
    $wp_object_cache->get($key, $group, $force, $found);
} else {
    error_log('WP_Object_Cache is not initialized.');
}

Заключение

Сложности, подобные вашей, могут возникать в процессе разработки плагинов и тем для WordPress. Важно следить за тем, чтобы архитектура кода соблюдала жизненный цикл WordPress, использовать хуки должным образом и избегать нестандартных подходов, таких как использование метода __destruct. Применение предложенных мер поможет устранить возникшую ошибку и улучшить стабильность вашего плагина.

Оцените материал
Добавить комментарий

Капча загружается...