web-dev-qa-db-fra.com

Indication de type pour n'importe quel objet

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?

49
GordonM

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.

46
Abdullah

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.

36
Gaz_Edge

Eh bien, cela n'a pris que huit ans, mais cela sera bientôt possible: PHP 7.2 introduit le conseil de type objectAu 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é

RFC: Object typehint

Discussion

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 ...

Voir https://3v4l.org/Svuij

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.

12
iainn

Bien qu'il n'y ait pas d'indication de type pour les objets, vous pouvez utiliser:

if (!is_object($arg)) {
    return;
}
11
Ben

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.

7
NikiC

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.

3
Jon

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

2
Ophidian

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
John

Erreur 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

1
lubosdz