J'ai travaillé sur du code destiné à être utilisé avec des objets, sans vraiment se soucier du type d'objet. Je voulais taper un indice que la méthode en cours d'écriture attendait un objet de tout type, mais rencontrait quelques difficultés.
J'ai essayé function myFunc (object $obj)
et function myFunc (stdClass $obj)
mais ces deux erreurs générées quand j'ai essayé de passer des objets dans:
Erreur fatale capturable: l'argument 1 passé à MyClass :: MyFunc () doit être une instance d'objet, une instance d'ObjectActualClass est donnée
La même chose s'est produite avec stdClass
également
Qu'est-ce que je rate? Je pensais que toutes les classes qui n'héritaient pas explicitement d'une autre classe héritée de stdClass
, ce qui signifie que la classe de base de chaque classe dans PHP serait stdClass
. Ce n'est pas le cas?
stdClass n'est PAS une classe de base! PHP n'héritent pas automatiquement d'une classe. Toutes les classes sont autonomes, sauf si elles étendent explicitement une autre classe. PHP diffère de nombreux langages orientés objet dans ce le respect.
La meilleure façon d'appliquer cela serait de créer une interface dégénérée appelée Object
. Une interface dégénérée signifie qu'elle n'a pas de méthodes définies.
interface Object {
// leave blank
}
Ensuite, dans vos classes de base, vous pouvez implémenter Object
.
class SomeBase implements Object {
// your implementation
}
Vous pouvez maintenant appeler votre fonction comme vous le souhaitez
function myFunc (Object $obj);
myFunc($someBase);
Si vous passez un objet qui hérite de votre interface Object
, ce conseil de type passera. Si vous passez un tableau, un entier, une chaîne, etc., l'indicateur de type échouera.
Eh bien, cela n'a pris que huit ans, mais cela sera bientôt possible: PHP 7.2 introduit le conseil de type object
! Au moment où j'écris ceci, il est actuellement au stade RFC, et devrait sortir en novembre .
Mise à jour du 30 novembre: PHP 7.2 a été publié
Cela se comporte exactement comme vous pouvez vous y attendre:
<?php
class Foo {}
class Bar {}
function takeObject(object $obj) {
var_dump(get_class($obj));
}
takeObject(new Foo);
takeObject(new Bar);
takeObject('not an object');
Aura pour résultat:
chaîne (3) "Foo"
chaîne (3) "Bar"
Erreur fatale: TypeError non capturé: l'argument 1 passé à takeObject () doit être un objet, une chaîne donnée, appelée dans ...
Un effet secondaire de ceci est que object
est maintenant un mot réservé , ce qui rend malheureusement la solution existante de @ Gaz_Edge ci-dessus cassé . Heureusement, tout ce que vous avez à faire pour y remédier est de supprimer l'interface.
Bien qu'il n'y ait pas d'indication de type pour les objets, vous pouvez utiliser:
if (!is_object($arg)) {
return;
}
Il n'y a pas de classe de base à partir de laquelle tous les objets s'étendent. Vous devez simplement supprimer le typehint et documenter le type attendu dans le @param
annotation.
Il n'y a pas de mécanisme intégré pour le faire sans exiger que tous les utilisateurs de votre interface étendent une classe spécifiée. Mais pourquoi voudriez-vous faire cela de toute façon? Qu'est-ce que tous les types d'objets ont en commun qui sont suffisants pour en faire une entrée appropriée pour votre API?
Selon toute probabilité, vous ne gagneriez rien même si vous pouviez taper un indice comme celui-ci. D'un autre côté, le type indiquant un paramètre pour implémenter une interface (tel que Traversable
) serait beaucoup plus significatif.
Si vous voulez toujours quelque chose qui ressemble à une indication de type, le mieux que vous puissiez faire est de remplacer une vérification d'exécution par is_object
sur le paramètre.
Depuis php 7.2, cette fonctionnalité est désormais implémentée. vous pouvez maintenant saisir un indice pour n'importe quel objet.
function myFunc(Object $myObject) : Object {
return $myObject;
}
Vous pouvez le consulter dans la documentation officielle
Typehint pour stdClass
fonctionne depuis PHP 5.3+ (si je ne me trompe pas). Voici un code valide utilisant typhint pour stdClass
construct:
Exemple test.php
:
class Test{
function hello(stdClass $o){
echo $o->name;
}
}
class Arg2 extends stdClass{
public $name = 'John';
function sayHello(){
echo 'Hello world!';
}
}
$Arg1 = new stdClass();
$Arg1->name = 'Peter';
$Arg2 = new Arg2();
$Arg2->sayHello();
$test = new Test();
// OK
$test->hello($Arg1);
$test->hello($Arg2);
// fails
$test->hello(1);
Imprime:
Bonjour le monde!
Peter
JohnErreur fatale capturable: l'argument 1 passé à Test :: hello () doit être une instance de stdClass, un entier donné, appelé dans test.php à la ligne 32 et défini dans test.php à la ligne 5