PHP : résoudre l’erreur « Creating default object from empty value »

Suite à une mise à jour de PHP, le fichier d’erreurs de mon site a commencé à afficher le message suivant :

PHP Warning: Creating default object from empty value in /wp-content/themes/skyminds/functions.php on line 1213

La ligne en question ressemblait à ceci :

$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

À première vue, cette ligne semble anodine. Pourtant, elle suppose plusieurs choses : que $posts existe, que $posts est un tableau, que l’index 0 existe, et que $posts[0] est bien un objet.

Si l’une de ces conditions n’est pas vraie, PHP tente parfois de créer un objet par défaut à partir d’une valeur vide. C’est ce qui déclenche l’avertissement Creating default object from empty value.

Kinsta: Premium Managed WordPress hosting

Pourquoi cette erreur apparaît

Le problème vient généralement d’une assignation de propriété sur une variable qui n’est pas un objet valide.

Exemple simple :

$post = null;
$post->comment_status = 'closed';Langage du code : PHP (php)

Ou encore :

$posts = array();
$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

Dans le second cas, $posts existe bien, mais $posts[0] n’existe pas. PHP ne peut donc pas modifier la propriété comment_status d’un objet absent.

La bonne correction dépend donc du type de donnée que vous manipulez : tableau, objet générique stdClass, instance de classe, ou objet WordPress comme WP_Post.

Correction rapide : vérifier que l’objet existe

La correction la plus prudente consiste à tester l’existence du premier élément avant de modifier sa propriété :

if ( isset( $posts[0] ) && is_object( $posts[0] ) ) {
    $posts[0]->comment_status = 'closed';
}Langage du code : PHP (php)

Cette version évite l’avertissement, car elle ne modifie comment_status que si $posts[0] existe et contient bien un objet.

Dans un thème WordPress, si l’on s’attend à recevoir un objet WP_Post, on peut être plus strict :

if ( isset( $posts[0] ) && $posts[0] instanceof WP_Post ) {
    $posts[0]->comment_status = 'closed';
}Langage du code : PHP (php)

C’est généralement préférable, car on vérifie le type exact attendu. WordPress documente WP_Post comme la classe utilisée pour représenter les objets d’articles retournés par des fonctions comme get_post().

Kinsta: Premium Managed WordPress hosting

Ne pas initialiser au hasard avec array() ou stdClass

Dans l’ancienne version de cet article, je proposais deux pistes :

$posts = new stdClass();Langage du code : PHP (php)

ou :

$posts = array();Langage du code : PHP (php)

Ces deux lignes peuvent être correctes, mais pas dans le même contexte.

Si votre code fait ceci :

$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

alors $posts doit être un tableau, et $posts[0] doit être un objet. Initialiser seulement $posts comme tableau vide ne suffit donc pas, car $posts[0] reste absent.

Si vous voulez créer manuellement cette structure, il faudrait plutôt faire :

$posts      = array();
$posts[0]   = new stdClass();
$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

Mais dans WordPress, ce n’est généralement pas ce que vous voulez faire. Si $posts est censé contenir des articles, il vaut mieux récupérer de vrais objets WP_Post ou vérifier que la requête a bien retourné un résultat.

Cas WordPress : vérifier le résultat d’une requête

Dans WordPress, cette erreur apparaît souvent après une requête qui ne retourne aucun article.

Par exemple :

$posts = get_posts(
    array(
        'post_type'      => 'post',
        'posts_per_page' => 1,
    )
);

$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

Si get_posts() retourne un tableau vide, $posts[0] n’existe pas. Il faut donc vérifier le résultat avant de l’utiliser :

$posts = get_posts(
    array(
        'post_type'      => 'post',
        'posts_per_page' => 1,
    )
);

if ( isset( $posts[0] ) && $posts[0] instanceof WP_Post ) {
    $posts[0]->comment_status = 'closed';
}Langage du code : PHP (php)

C’est déjà mieux, mais il faut se poser une autre question : souhaitez-vous seulement modifier l’objet en mémoire, ou voulez-vous réellement fermer les commentaires dans la base de données ?

Kinsta: Premium Managed WordPress hosting

Modifier l’objet ne modifie pas forcément la base de données

La ligne suivante modifie la propriété de l’objet PHP en mémoire :

$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

Mais elle ne met pas forcément à jour l’article dans la base de données.

Pour fermer réellement les commentaires d’un article WordPress, utilisez plutôt wp_update_post() :

$posts = get_posts(
    array(
        'post_type'      => 'post',
        'posts_per_page' => 1,
        'fields'         => 'ids',
    )
);

if ( ! empty( $posts[0] ) ) {
    wp_update_post(
        array(
            'ID'             => (int) $posts[0],
            'comment_status' => 'closed',
        )
    );
}Langage du code : PHP (php)

Cette version est plus claire : on récupère un ID, puis on demande à WordPress de mettre à jour l’article. C’est beaucoup plus propre que de modifier directement un objet retourné par une requête.

Version WPCS et PHP 8.3+

Voici une version plus propre, compatible avec PHP moderne et les standards WordPress :

<?php
/**
 * Close comments for the latest post matching a query.
 *
 * @return void
 */
function sky_close_comments_for_latest_post(): void {
	$post_ids = get_posts(
		array(
			'post_type'              => 'post',
			'post_status'            => 'publish',
			'posts_per_page'         => 1,
			'fields'                 => 'ids',
			'no_found_rows'          => true,
			'update_post_meta_cache' => false,
			'update_post_term_cache' => false,
		)
	);

	if ( empty( $post_ids[0] ) ) {
		return;
	}

	wp_update_post(
		array(
			'ID'             => (int) $post_ids[0],
			'comment_status' => 'closed',
		)
	);
}Langage du code : HTML, XML (xml)

Ici, on évite de manipuler directement $posts[0]->comment_status. On demande à WordPress de faire la mise à jour correctement.

Les options no_found_rows, update_post_meta_cache et update_post_term_cache évitent du travail inutile si l’on ne veut récupérer qu’un ID. C’est plus léger et plus explicite.

Kinsta: Premium Managed WordPress hosting

Cas général PHP : objet ou tableau ?

Hors WordPress, la règle reste la même : il faut savoir si l’on manipule un objet ou un tableau.

Si vous voulez un objet générique :

$post = new stdClass();
$post->comment_status = 'closed';Langage du code : PHP (php)

stdClass est la classe générique vide de PHP. Elle accepte les propriétés dynamiques, contrairement aux classes modernes qui peuvent déclencher des avertissements en PHP 8.2+ si l’on ajoute des propriétés non déclarées. PHP documente d’ailleurs que stdClass est exempté de la dépréciation des propriétés dynamiques.

Si vous voulez un tableau associatif :

$post = array();
$post['comment_status'] = 'closed';Langage du code : PHP (php)

Mais il ne faut pas mélanger les deux syntaxes :

// Objet.
$post->comment_status = 'closed';

// Tableau.
$post['comment_status'] = 'closed';Langage du code : PHP (php)

Si vous utilisez la flèche ->, vous travaillez avec un objet. Si vous utilisez les crochets [], vous travaillez avec un tableau.

PHP 8.2 et les propriétés dynamiques

Depuis PHP 8.2, la création de propriétés dynamiques sur une classe qui ne les déclare pas est dépréciée, sauf exceptions. PHP indique que cette dépréciation peut être corrigée en déclarant la propriété, en utilisant l’attribut #[AllowDynamicProperties], ou en s’appuyant sur des méthodes magiques comme __get() et __set().

Exemple problématique :

class Post_Data {
}

$post = new Post_Data();
$post->comment_status = 'closed';Langage du code : PHP (php)

En PHP 8.2+, ce code peut déclencher :

Deprecated: Creation of dynamic property Post_Data::$comment_status is deprecatedLangage du code : PHP (php)

La bonne correction consiste à déclarer la propriété :

class Post_Data {
    public string $comment_status = 'open';
}

$post = new Post_Data();
$post->comment_status = 'closed';Langage du code : PHP (php)

Ou à utiliser un tableau si le modèle de données est réellement dynamique :

$post_data = array(
    'comment_status' => 'closed',
);Langage du code : PHP (php)

Donc, aujourd’hui, je déconseille de corriger ce type d’erreur en créant des propriétés à la volée sur n’importe quel objet. Cela peut fonctionner en PHP 7, puis se transformer en avertissement en PHP 8.2, et probablement en problème plus sérieux à terme.

Erreur liée à E_STRICT : nuance importante

Dans l’ancienne explication, j’évoquais E_STRICT. C’était vrai dans le contexte des anciennes versions de PHP, mais la situation a changé.

Depuis PHP 8.0, la valeur par défaut de error_reporting est E_ALL, alors qu’avant PHP 8.0 la configuration recommandée pour la production excluait notamment E_DEPRECATED et E_STRICT. La documentation PHP indique également que la valeur par défaut de error_reporting est désormais E_ALL.

En pratique, une mise à jour de PHP peut donc faire apparaître des avertissements ou dépréciations qui existaient déjà dans le code, mais qui n’étaient pas visibles auparavant.

La solution n’est pas de masquer les erreurs, mais de corriger les types et les structures de données. C’est moins agréable sur le moment, mais bien meilleur pour la santé du code.

Ne pas masquer l’erreur avec @

On pourrait être tenté d’écrire ceci :

@$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

À éviter. L’opérateur @ masque l’erreur, mais il ne corrige pas le problème. Vous aurez toujours une variable dans un état inattendu, simplement avec moins de bruit dans les logs.

En développement, les logs sont là pour signaler un problème réel. Les faire taire revient à mettre du scotch sur un voyant rouge. Très décoratif, rarement mécanique.

Comment diagnostiquer rapidement

Avant de corriger, inspectez le type réel de la variable :

var_dump( $posts );Langage du code : PHP (php)

Dans WordPress, évitez d’afficher cela en production. Préférez le log :

error_log( print_r( $posts, true ) );Langage du code : PHP (php)

Ou une vérification plus ciblée :

error_log( gettype( $posts ) );

if ( isset( $posts[0] ) ) {
    error_log( gettype( $posts[0] ) );
}Langage du code : PHP (php)

Vous saurez alors si vous manipulez un tableau vide, un objet, un tableau d’objets, ou une valeur inattendue.

Mémo rapide

// Problème courant.
$posts[0]->comment_status = 'closed';

// Correction minimale.
if ( isset( $posts[0] ) && is_object( $posts[0] ) ) {
    $posts[0]->comment_status = 'closed';
}

// Correction WordPress plus stricte.
if ( isset( $posts[0] ) && $posts[0] instanceof WP_Post ) {
    $posts[0]->comment_status = 'closed';
}

// Si l’on veut vraiment créer un tableau contenant un objet.
$posts    = array();
$posts[0] = new stdClass();
$posts[0]->comment_status = 'closed';

// Si l’on veut un tableau associatif.
$post = array();
$post['comment_status'] = 'closed';

// Si l’on veut modifier réellement un article WordPress.
wp_update_post(
    array(
        'ID'             => 123,
        'comment_status' => 'closed',
    )
);Langage du code : PHP (php)

Conclusion

L’erreur Creating default object from empty value apparaît lorsque PHP tente d’assigner une propriété à une valeur qui n’est pas un objet valide.

Dans l’exemple suivant :

$posts[0]->comment_status = 'closed';Langage du code : PHP (php)

il faut vérifier que $posts est bien un tableau, que $posts[0] existe, et que $posts[0] est bien un objet.

Dans WordPress, si l’objectif est de fermer les commentaires d’un article, la meilleure solution consiste souvent à utiliser wp_update_post() plutôt que de modifier directement une propriété d’objet.

Le bon réflexe est donc simple : ne corrigez pas l’erreur en initialisant une variable au hasard. Vérifiez le type attendu, testez l’existence de la donnée, puis utilisez l’API adaptée. PHP râle, certes, mais cette fois il a plutôt raison.

Demandez à l'IA son opinion
Gravatar for Matt Biscay

Je suis Matt Biscay, développeur WordPress & WooCommerce certifié chez Codeable, administrateur système et enseignant.

J’aide les entreprises à créer, optimiser et fiabiliser leurs sites WordPress avec une approche technique propre : performance, sécurité, maintenance, développement sur mesure et résolution de problèmes complexes.

Sur Skyminds, je partage des tutoriels WordPress, WooCommerce, Linux et administration système, avec des solutions testées sur des cas réels et pensées pour durer.

Découvrez mes services WordPress et WooCommerce.

1 réflexion au sujet de « PHP : résoudre l’erreur « Creating default object from empty value » »

  1. Je viens d’avoir cette erreur en passant en prod un site sous codeigniter (aucun warning en dev) et aucune des 2 solutions ne passe malheureusement.
    Est ce que depuis tu aurais trouvé une autre solution supplémentaire?
    Merci

    Répondre

Laisser un commentaire