Tout comme nous le faisons avec __ToString, existe-t-il un moyen de définir une méthode pour le casting ?
$obj = (MyClass) $another_class_obj;
Tout comme nous le faisons avec __ToString, existe-t-il un moyen de définir une méthode pour le casting ?
$obj = (MyClass) $another_class_obj;
Il n'est pas nécessaire de taper cast en php.
Editar: Puisque ce sujet semble susciter une certaine confusion, je me suis dit que j'allais élaborer un peu plus.
Dans des langages tels que Java, deux éléments peuvent porter un type. Le compilateur a une notion du type, et le temps d'exécution a une autre idée des types. Les types du compilateur sont liés aux variables, tandis que le moteur d'exécution suit le type des valeurs (qui sont assignées aux variables). Les types des variables sont connus au moment de la compilation, alors que les types des valeurs ne sont connus qu'au moment de l'exécution.
Si un morceau de code en entrée viole le système de types du compilateur, ce dernier se rebiffe et arrête la compilation. En d'autres termes, il est impossible de compiler un morceau de code qui viole le système de types statique. Cela permet de détecter une certaine catégorie d'erreurs. Par exemple, prenez le morceau de code Java (simplifié) suivant :
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
Si on faisait ça maintenant :
Alpha a = new Beta();
nous serions bien, puisque Beta
est une sous-classe de Alpha
et donc une valeur valide pour la variable a
de type Alpha
. Cependant, si nous procédons :
a.sayHello();
Le compilateur donnerait une erreur, puisque la méthode sayHello
n'est pas une méthode valide pour Alpha
- Peu importe que nous sachions que a
est en fait un Beta
.
Entrez le type de casting :
((Beta) a).sayHello();
Ici, nous indiquons au compilateur que la variable a
devrait - dans ce cas - être traitée comme une Beta
. C'est ce qu'on appelle le "type casting". Cette échappatoire est très utile, car elle permet le polymorphisme dans le langage, mais évidemment, c'est aussi une porte dérobée pour toutes sortes de violations du système de types. Afin de maintenir une certaine sécurité de type, il y a donc quelques restrictions ; Vous pouvez seulement faire un casting vers des types qui sont liés. Par exemple, en haut ou en bas d'une hiérarchie. En d'autres termes, vous ne pouvez pas faire un cast vers une classe complètement indépendante. Charlie
.
Il est important de noter que tout cela se passe dans le compilateur, c'est-à-dire avant même l'exécution du code. Java peut toujours avoir des erreurs de type d'exécution. Par exemple, si vous faites ceci :
class Alpha {}
class Beta extends Alpha {
public void sayHello() {
System.out.println("Hello");
}
}
class Charlie extends Alpha {}
Alpha a = new Charlie();
((Beta) a).sayHello();
Le code ci-dessus est valide pour le compilateur, mais au moment de l'exécution, vous obtiendrez une exception, puisque le cast de Beta
a Charlie
est incompatible.
Pendant ce temps, de retour à la ferme PHP.
Ce qui suit est valable pour le compilateur PHP - Il le transformera volontiers en code d'octet exécutable, mais vous obtiendrez une erreur d'exécution :
class Alpha {}
class Beta extends Alpha {
function sayHello() {
print "Hello";
}
}
$a = new Alpha();
$a->sayHello();
C'est parce que les variables PHP n'ont pas de type. Le compilateur n'a aucune idée des types valides pour une variable, donc il n'essaie pas de les faire respecter. Vous ne spécifiez pas non plus le type explicitement comme en Java. Il y a des indications de type, oui, mais ce sont simplement des contrats d'exécution. Ce qui suit est toujours valable :
// reuse the classes from above
function tellToSayHello(Alpha $a) {
$a->sayHello();
}
tellToSayHello(new Beta());
Même si PHP variables n'ont pas de types, les valeurs le font encore. Un aspect particulièrement intéressant de PHP, est qu'il est possible de changer le type d'une valeur. Par exemple :
// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
settype($foo, "integer");
echo gettype($foo); // Yields "integer"
Cette fonction est parfois confondue avec le moulage de type, mais c'est une erreur. Le type est toujours une propriété de la valeur, et le changement de type se produit au moment de l'exécution, et non au moment de la compilation.
La possibilité de changer de type est également assez limitée en PHP. Il est seulement possible de changer de type entre des types simples - pas entre des objets. Ainsi, il n'est pas possible de changer le type d'une classe à une autre. Vous pouvez créer un nouvel objet et copier l'état, mais changer le type n'est pas possible. PHP est un peu à part dans ce domaine ; d'autres langages similaires traitent les classes comme un concept beaucoup plus dynamique que PHP.
Une autre caractéristique similaire de PHP est que vous pouvez cloner une valeur comme un nouveau type, comme ceci :
// The variable $foo holds a value with the type of string
$foo = "42";
echo gettype($foo); // Yields "string"
// Here we change the type from string -> integer
$bar = (integer) $foo;
echo gettype($bar); // Yields "integer"
Syntaxiquement, cela ressemble beaucoup à la façon dont un typecast est écrit dans les langages typés statiquement. C'est pourquoi on le confond souvent avec le type casting, même s'il s'agit toujours d'une conversion de type à l'exécution.
Pour résumer : Le casting de type est une opération qui permet de changer le type d'une variable ( no la valeur). Comme les variables n'ont pas de type en PHP, ce n'est pas seulement impossible à faire, mais c'est une question absurde à poser.
C'est le cas si vous voulez passer d'une classe définie par l'utilisateur à une autre. Il y a un moyen de le faire, je l'ai déjà fait auparavant.
Les variables en PHP ne sont pas typées ; seuls les objets auxquels elles font référence ont un type. En tant que tel, vous ne peut pas taper une variable en php.
Bien qu'il ne soit pas nécessaire d'utiliser le cast en PHP, vous pouvez rencontrer une situation où vous souhaitez convertir un objet parent en objet enfant.
//Example of a sub class
class YourObject extends MyObject {
public function __construct(MyObject $object) {
foreach($object as $property => $value) {
$this->$property = $value;
}
}
}
$my_object = new MyObject();
$your_object = new YourObject($my_object);
Ainsi, tout ce que vous faites est de passer l'objet parent au constructeur de l'objet enfant, et de laisser le constructeur copier les propriétés. Vous pouvez même les filtrer / modifier si nécessaire.
//Class to return standard objects
class Factory {
public static function getObject() {
$object = new MyObject();
return $object;
}
}
//Class to return different object depending on the type property
class SubFactory extends Factory {
public static function getObject() {
$object = parent::getObject();
switch($object->type) {
case 'yours':
$object = new YourObject($object);
break;
case 'ours':
$object = new OurObject($object);
break;
}
return $object;
}
}
//Example of a sub class
class YourObject extends MyObject {
public function __construct(MyObject $object) {
foreach($object as $property => $value) {
$this->$property = $value;
}
}
}
Ce n'est pas du type casting, mais ça fait ce dont vous avez besoin.
J'ai retravaillé la fonction que Josh a postée (qui va se planter à cause de la variable indéfinie $new_class). Voici ce que j'ai obtenu :
function changeClass(&$obj, $newClass)
{ $obj = unserialize(preg_replace // change object into type $new_class
( "/^O:[0-9]+:\"[^\"]+\":/i",
"O:".strlen($newClass).":\"".$newClass."\":",
serialize($obj)
));
}
function classCast_callMethod(&$obj, $newClass, $methodName, $methodArgs=array())
{ $oldClass = get_class($obj);
changeClass($obj, $newClass);
// get result of method call
$result = call_user_func_array(array($obj, $methodName), $methodArgs);
changeClass(&$obj, $oldClass); // change back
return $result;
}
Ça fonctionne comme on s'attend à ce qu'une distribution de classe fonctionne. Vous pourriez construire quelque chose de similaire pour accéder aux membres d'une classe - mais je ne pense pas que j'en aurai jamais besoin, donc je laisse cela à quelqu'un d'autre.
Bravo à tous les abrutis qui disent "php ne fait pas de casting" ou "vous n'avez pas besoin de faire de casting en php". C'est du pipeau. Le casting est une partie importante de la vie orientée objet, et j'aimerais pouvoir trouver une meilleure façon de le faire que d'affreux bidouillages de sérialisation.
Alors merci Josh !
Juste une remarque, j'ajouterais une exception dans changeClass si la classe casted vers n'est pas une classe parente. Cela inclut les classes qui n'existent pas. Mais le code que j'ai ci-dessus est à peu près le plus simple que l'on puisse obtenir pour un cast fonctionnel, à ma connaissance.
La seule chose pour laquelle j'utiliserais le casting en php, est de permettre à l'IDE de connaître le type de l'objet afin que l'IDE puisse autocompléter les propriétés d'une instance de classe C'est tout.
Tout cela est bien beau pour vous Janov, mais si vous construisez une interface complexe qui n'est pas incroyablement verbeuse, vous avez parfois besoin d'une petite astuce. I avait pour utiliser le casting de classe pour une couche d'abstraction de base de données que j'ai créée. Sinon, il n'y aurait eu aucun moyen de gérer convenablement le sous-classement.
Voici une fonction pour changer la classe d'un objet :
/**
* Change the class of an object
*
* @param object $obj
* @param string $class_type
* @author toma at smartsemantics dot com
* @see http://www.php.net/manual/en/language.types.type-juggling.php#50791
*/
function changeClass(&$obj,$new_class)
{
if(class_exists($class_type,true))
{
$obj = unserialize(preg_replace("/^O:[0-9]+:\"[^\"]+\":/i",
"O:".strlen($class_type).":\"".$new_class."\":", serialize($obj)));
}
}
Au cas où ce n'est pas clair, ce n'est pas ma fonction, elle a été prise d'un post par "toma at smartsemantics dot com" sur http://www.php.net/manual/en/language.types.type-juggling.php#50791
Ce n'est pas un modèle. C'est un changement de type de l'objet - pas de la variable. En PHP, vous ne pouvez pas faire de typecast, puisque les variables n'ont pas de type.
Je suis d'accord, ma fonction change la classe de l'objet. C'est ce que l'auteur de la question voulait. Et selon le manuel PHP, les variables faire ont des types et le typage est possible : us.php.net/manuel/fr/
D'accord ; vous pouvez changer le type d'une primitive. Mais vous ne pouvez pas changer le type d'un objet. Indépendamment de la formulation dans le manuel, les variables font no avoir le type en php. Ils font référence à des valeurs qui ont un type.
Je pense que vous devez taper le casting afin de faire un meilleur IDE. Mais le langage php lui-même n'a pas besoin d'un casting de type, il supporte cependant les changements de type à l'exécution pour les valeurs des variables. Jetez un oeil à autoboxing et unboxing. C'est ce que php fait de manière inhérente. Donc, désolé, ce n'est pas mieux que les IDEs existants.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
5 votes
Pourquoi voudriez-vous couler quelque chose en PHP ? Vous pouvez simplement appeler les méthodes que vous voulez de toute façon.
5 votes
Vous ne pouvez pas appeler ces méthodes si elles n'existent pas dans la classe. Il se peut que vous deviez effectuer un typecast d'une classe d'utilisateur à une autre afin d'appeler les fonctions directement en utilisant l'opérateur ->.
0 votes
Josh, dans ce cas, il doit y avoir un problème dans le flux de l'application.
0 votes
Je pense que votre jugement est peut-être hâtif ; cependant, je suis d'accord pour dire que la solution de gnarf pour créer un nouvel objet est meilleure car elle permet une logique de conversion entre les classes.