Comment résoudre «doit être une instance de chaîne, chaîne donnée» avant PHP 7?

217

Voici mon code:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

Ce qui entraîne cette erreur:

Erreur fatale capturable: l'argument 1 passé à phpwtf () doit être une instance de chaîne, chaîne donnée

C'est plus qu'un peu orwellien de voir PHP reconnaître et rejeter le type souhaité dans le même souffle. Il y a cinq lumières, bon sang.

Quel est l'équivalent de l'indication de type pour les chaînes en PHP? Bonus à la réponse qui explique exactement ce qui se passe ici.

leepowers
la source
5
Eh bien, c'est parce que vous vous trompez. Votre code n'est pas censé fonctionner, pour commencer. Lisez sur le jonglage de types dans les documents PHP. PHP est de type dynamique et de type faible. Vous pouvez utiliser (chaîne) pour convertir un argument en chaîne (uniquement dans le corps de la fonction), mais vous ne pouvez suggérer que des objets et des tableaux comme vous le faites dans votre extrait de code.
Richard Knop
7
Le problème est que vous avez fait une petite erreur. Il y a quatre lumières!
CJ Dennis
@Gordon, j'ai testé sur 5.6. Toujours pas de chance.
Pacerier
@Pacerier Veuillez suivre wiki.php.net/rfc pour les derniers développements.
Gordon
3
Apparemment, une indication de type scalaire (comme OP devrait intuitivement être une chose ci-dessus) a finalement été approuvée par un RFC pour PHP * 7 * selon la source . La RFC approuvée fournit apparemment également du sucre syntaxique pour les valeurs de retour de vérification de type ainsi que des paramètres (arguments). Ça a été long à venir.
SeldomNeedy

Réponses:

204

Avant PHP 7, l' indication de type ne peut être utilisée que pour forcer les types d'objets et de tableaux. Les types scalaires ne sont pas indexables. Dans ce cas, un objet de la classe stringest attendu, mais vous lui donnez un (scalaire) string. Le message d'erreur peut être drôle, mais il n'est pas censé fonctionner pour commencer. Étant donné le système de typage dynamique, cela a en fait une sorte de sens perverti.

Vous ne pouvez manuellement "taper l'indice" que les types scalaires:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}
décomposer
la source
1
@deceze, Existe-t-il une syntaxe pour les indications de type inversé? Par exemple, tout sauf les tableaux.
Pacerier
@Pacerier Non, il n'y en a pas.
décomposer
4
Cette réponse n'est pas valable pour PHP 7
Jose Nobile
24

Depuis le manuel de PHP :

Les indices de type ne peuvent être que de type objet et tableau (depuis PHP 5.1). L'indication de type traditionnel avec int et chaîne n'est pas prise en charge.

Vous l'avez donc. Le message d'erreur n'est pas vraiment utile, je vous le donne quand même.

** 2017 Modifier **

PHP7 a introduit plus de déclarations de type de données de fonction, et le lien susmentionné a été déplacé vers les arguments de fonction: déclarations de type . De cette page:

Types valides

  • Nom de classe / interface : Le paramètre doit être une instance du nom de classe ou d'interface donné. (depuis PHP 5.0.0)
  • self : le paramètre doit être une instance de la même classe que celle sur laquelle la méthode est définie. Cela ne peut être utilisé que sur les méthodes de classe et d'instance. (depuis PHP 5.0.0)
  • tableau : le paramètre doit être un tableau. (depuis PHP 5.1.0) callable Le paramètre doit être un callable valide. PHP 5.4.0
  • bool : Le paramètre doit être une valeur booléenne. (depuis PHP 7.0.0)
  • float : le paramètre doit être un nombre à virgule flottante. (depuis PHP 7.0.0)
  • int : le paramètre doit être un entier. (depuis PHP 7.0.0)
  • chaîne : Le paramètre doit être une chaîne. (depuis PHP 7.0.0)
  • itérable : le paramètre doit être un tableau ou une instance de Traversable. (depuis PHP 7.1.0)

avertissement

Les alias pour les types scalaires ci-dessus ne sont pas pris en charge. Au lieu de cela, ils sont traités comme des noms de classe ou d'interface. Par exemple, l'utilisation de booléen comme paramètre ou type de retour nécessitera un argument ou une valeur de retour qui est une instance de la classe ou de l'interface booléenne, plutôt que de type bool:

<?php
   function test(boolean $param) {}
   test(true);
 ?>

L'exemple ci-dessus affichera:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

Le dernier avertissement est en fait significatif pour comprendre l'erreur "L'argument doit être de type chaîne, chaîne donnée"; puisque la plupart du temps, seuls les noms de classe / interface sont autorisés comme type d'argument, PHP essaie de localiser un nom de classe "chaîne", mais ne peut en trouver car il s'agit d'un type primitif, échouez donc avec cette erreur gênante.

Yanick Rochon
la source
8

PHP permet "d'indiquer" où vous fournissez une classe pour spécifier un objet. Selon le manuel PHP, "Les conseils de type ne peuvent être que du type objet et tableau (depuis PHP 5.1). Les conseils de type traditionnel avec int et chaîne ne sont pas pris en charge." L'erreur est déroutante en raison de votre choix de "chaîne" - mettez "maClasse" à sa place et l'erreur se lira différemment: "L'argument 1 passé à phpwtf () doit être une instance de maClasse, chaîne donnée"

Rêves surréalistes
la source
3

Comme d'autres l'ont déjà dit, les indications de type ne fonctionnent actuellement que pour les types d'objet. Mais je pense que l'erreur particulière que vous avez déclenchée pourrait être en préparation du prochain type de chaîne SplString .

En théorie, il se comporte comme une chaîne, mais puisqu'il s'agit d'un objet, il passerait la vérification du type d'objet. Malheureusement, il n'est pas encore en PHP 5.3, pourrait arriver en 5.4, alors ne l'avez pas testé.

mario
la source
2

Comme des déclarations de type PHP 7.0 permettent les types scalaires, de sorte que ces types sont disponibles: self, array, callable, bool, float, int, string. Les trois premiers étaient disponibles en PHP 5, mais les quatre derniers sont nouveaux en PHP 7. Si vous utilisez autre chose (par exemple integerou boolean) qui sera interprété comme un nom de classe.

Voir le manuel PHP pour plus d'informations .

TwoStraws
la source
0

Peut-être pas sûr et joli mais si vous devez:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

    public function __toString()
    {
        return $this->Text;
    }
}

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));
Patrick
la source
5
Je pourrais encore créer unnew string(array(1,2,3))
Jimmy T.
0

J'ai eu cette erreur lors de l'appel d'une fonction d'un contrôleur Laravel à un fichier PHP.

Après quelques heures, j'ai trouvé le problème: j'utilisais $ this depuis une fonction statique.

ecairol
la source
Using $this when not in object contextest en effet un message cryptique.
Ben Fransen
0

(initialement publié par leepowers dans sa question)

Le message d'erreur prête à confusion pour une grande raison:

Les noms de types primitifs ne sont pas réservés en PHP

Voici toutes les déclarations de classe valides:

class string { }
class int { }
class float { }
class double { }

Mon erreur était de penser que le message d'erreur faisait uniquement référence au type de chaîne primitive - le mot «instance» aurait dû me donner une pause. Un exemple pour illustrer davantage:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Production:

$ s1 - chaîne primitive? oui - instance de chaîne? non

$ s2 - chaîne primitive? non - instance de chaîne? Oui

En PHP, il est possible que a stringsoit un stringsauf quand c'est réellement un string. Comme pour tout langage qui utilise une conversion de type implicite, le contexte est tout.

user719662
la source
-1

Je pense que le transtypage sur php sur le bloc intérieur, String sur PHP n'est pas un objet comme je le sais:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");
subosito
la source
2
Vous pouvez ajouter la validation is_string () à l'intérieur de votre fonction pour empêcher toute autre valeur transmise à la fonction.
subosito
1
(string) $speut lancer une erreur s'il $ss'agit d'un objet qui ne peut pas être converti en chaîne (aucune __toString()méthode n'est implémentée), donc ce n'est pas aussi simple que cela
Yanick Rochon
Oui Yanick tu as raison. Mais nous ne pouvons pas forcer toutes les entrées à être des chaînes, n'est-ce pas? c'est pourquoi l'exception vient jouer. Nous pouvons combiner sorte de validations et attraper l'exception pour le reste;)
subosito
Je dis juste que la conversion d'une variable en chaîne sans vérifier d'abord si la variable peut être convertie doit être évitée, principalement parce que la capture d'exceptions est coûteuse et conduit à de mauvais modèles de conception / habbits de codage.
Yanick Rochon