La méthode require renvoie un entier lorsque ce n'est pas possible en PHP
P粉883223328
2023-09-02 09:55:14
<p>J'ai le code suivant qui enregistre du code php dans un fichier, puis le charge et l'exécute à nouveau et parfois la méthode require renvoie un int, pourquoi cela se produit-il ? </p>
<h1>demo.php</h1>
<pre class="brush:php;toolbar:false;"><?php
$f = fonction() utiliser($a){
$cachePath = '/tmp/t.php';
$code = '<?php';
$code .= "nn";
$code .= 'retour ' . var_export([], vrai) ';';
file_put_contents($cachePath, $code, LOCK_EX);
if (file_exists($cachePath)) {
// Parfois, la ligne suivante renvoie un entier, pourquoi ?
$result = require($cachePath);
si (!is_array($result)) {
var_dump($result, $cachePath, file_get_contents($cachePath));
quitter("ok");
}
var_dump ($ résultat);
}
} ;
pour($i=0;$i<1000000;$i++) {
$f();
}</pré>
<h1>Comment reproduire ? </h1>
<p>Utilisez deux processus php pour exécuter le code ci-dessus</p>
<pre class="brush:php;toolbar:false;">php demo.php</pre></p>
Voici la documentation de
require
的标准行为,与include
, le comportement est le même entre les deux :Comme vous pouvez le voir, lorsque la valeur de retour n'est pas écrasée, un entier (1) est renvoyé sur le chemin heureux.
Cela a du sens pour votre exemple, jusqu'à présent le fichier existe (donc pas d'erreur fatale), mais comme le fichier vient d'être créé, il se peut qu'il soit simplement tronqué, c'est-à-dire qu'il est vide. p>
Ainsi, la valeur de retour n'est pas écrasée et vous pouvez voir le int(1).
Une autre explication est naturellement que vous avez écrasé avec des nombres entiers, ce qui est également possible puisque plusieurs processus peuvent écrire dans le même fichier, mais avec la façon dont vous avez écrit votre exemple, c'est moins probable. Je le mentionne seulement parce que c'est une autre explication valable.
contient si présent
Exemple comment suspendre une condition de concurrence critique lorsque vous recherchez
$result
au lieu de (uniquement) lorsque le fichier existe :L'idée derrière cela est que nous faisons très peu de gestion des erreurs, comme vérifier si le fichier existe, sinon il ne peut pas être inclus (include() émet simplement un avertissement et le transmet avec $result = false), et ensuite si $ le résultat est chargé, il le fait. S'applique aux tests is_array().
C'est ce que nous avons pour les erreurs, mais nous savons ce que nous recherchons, c'est-à-dire que $result est un tableau.
C'est ce qu'on appelle souvent une transaction ou une opération de transaction.
Dans ce nouvel exemple, nous n'entrons même pas le if-body lorsque le tableau $result est vide, c'est-à-dire qu'il ne contient aucune donnée.
Au niveau du traitement du programme, qui pourrait nous intéresser, la présence ou l'absence d'un fichier, être vide ou non, ou même être mal écrit sont autant de conditions d'erreur qui doivent être "mangées" et invalider le $result.
L'erreur de définition n'existe pas.
Gestion des erreurs d'analyse (pour Include-If-Exists)
Depuis PHP 7.0, nous pouvons utiliser include() et si malheureusement le fichier include renvoyé est à moitié écrit, nous verrons une erreur d'analyse PHP qui peut être attrapée :
Veuillez vous référer à PHP try-catch-finally pour savoir comment lancer des exceptions/travail de gestion des exceptions en détail, assert() est utilisé pour enregistrer la signification du paramètre d'entrée $cachePath dans l'exemple.
Le deuxième exemple n'utilise pas l'opération de suppression "@", la raison est que si vous l'utilisez comme l'exemple précédent, et que le fichier à inclure contiendra une véritable erreur fatale, l'erreur fatale sera réduite au silence. De nos jours, dans PHP moderne, ce n'est plus un gros problème, mais utiliser file_exists() + include() - bien qu'il existe une condition de concurrence due au temps de vérification par rapport au temps d'utilisation - est sûr (seulement un avertissement) pour les fichiers inexistants. et les erreurs fatales ne sont pas cachées.
Comme vous l'avez peut-être vu, plus vous connaissez de détails, plus il est difficile d'écrire un code aussi évolutif que possible. Nous ne devons pas nous perdre dans la gestion des erreurs elle-même, mais nous concentrer sur les résultats et définir que ces erreurs n'existent pas.
Cela dit, include() provoque toujours le chargement des données en mémoire, file_exists() n'est utilisé que pour "supprimer" les avertissements, nous savons que, néanmoins, include() peut émettre des avertissements et renvoyer un entier au lieu d'un tableau .
Maintenant, puisque la programmation est difficile : vous pouvez alors l'enrouler en boucle et dire de réessayer trois fois. Pourquoi ne pas utiliser une boucle for pour compter et protéger les tentatives numériques ?
Ce problème ne peut pas être reproduit si le script n'a toujours qu'un seul exécuteur.
Si vous parlez d'exécuter ce script en parallèle, le problème est que l'écriture du fichier en mode exclusif ne vous protège pas de la lecture du fichier ultérieurement pendant le processus d'écriture.
Le processus peut écrire dans le fichier (et posséder le verrou), mais
require
ne pas honorer le verrou (les verrous du système de fichiers sont consultatifs et non appliqués).La bonne solution est donc :
Notez que le verrou n'est pas libéré ni réacquis après l'écriture, car un autre processus peut attendre pour écraser le fichier.
Ne pas le publier pour garantir que le même morceau de code écrit est également
require
d.Cependant, tout cela était discutable dès le départ.
Pourquoi dois-je écrire dans un fichier pour qu'il puisse être renvoyé plus tard
require
?