47 votes

Comment débrider un objet en Perl ?

De perldoc -f bless :

bless REF,CLASSNAME

Cette fonction indique à la chose référencée par REF qu'il est maintenant
un objet dans le CLASSNAME l'emballage.

Existe-t-il un moyen d'obtenir une structure non bénite sans faire de copies inutiles ?

1 votes

0 votes

@Ether : Par exemple, Template::Toolkit. L'opérateur point '.' est utilisé pour accéder à des listes et à des hachages ou pour appeler des méthodes d'objets. TT essaie toujours une méthode objet en premier.

4 votes

Pour information, j'ai besoin de unbless parce que YAML::Any::Dump() conservera la nature bénite d'un objet, je ne veux pas stocker cela, mais parfois les hachages de données que je déverse sont bénis. Aussi Moose->new est très pointilleux et ne prend pas une hashref bénite comme argument.

41voto

Sinan Ünür Points 76179

Data::Structure::Util

unbless($ref)

Retirer la bénédiction de tous les objets trouvés dans la structure de données transmise.

#!/usr/bin/perl

use strict; use warnings;

use Scalar::Util qw( refaddr );
use Data::Structure::Util qw( unbless );

my $x = bless { a => 1, b => 2 } => 'My';

printf "%s : %s\n", ref $x, refaddr $x;

unbless $x;

printf "%s : %s\n", ref $x, refaddr $x;

Sortie :

My : 237356
HASH : 237356

34voto

brian d foy Points 71781

Data::Structure::Util dispose d'un unbless qui le fera pour vous. Comme le souligne Erik, JSON::XS n'accepte normalement pas les références bénies (même si j'aimerais qu'il l'ignore et qu'il s'occupe de la structure de données). Il n'y a pas de moyen de contourner ce problème dans ce cas.

Mais réfléchissez à la raison pour laquelle vous pensez qu'il est nécessaire de le débloquer. Faites-vous cela pour l'une de vos propres classes ou pour une classe différente ? Cela ressemble étrangement à la mauvaise chose à faire. Il y a peut-être une meilleure solution.

Vous avez le même problème que la rupture de l'encapsulation car vous devez supposer que vous connaissez la structure interne de la référence. Si vous faites cela, vous pouvez simplement ignorer l'aspect orienté objet et accéder directement à la structure.

Si vous comptez le faire dans votre propre classe, envisagez de fournir une méthode permettant de renvoyer une structure de données (qui ne doit pas nécessairement être la structure d'origine) au lieu de modifier l'objet.

Vous mentionnez dans un commentaire de suivi que vous pourriez faire cela pour contourner certains comportements de Template Toolkit. J'ai fait face à cette situation de deux manières différentes, en fonction de la situation :

  • Ne transmettez au modèle que les données dont vous avez besoin plutôt que l'objet entier.
  • Ajoutez des méthodes à l'objet pour obtenir les données que vous souhaitez dans le modèle.

Perl est DWIM, mais TT est encore plus DWIM, ce qui est parfois regrettable.


Voici une petite astuce qui consiste à définir un fichier TO_JSON en UNIVERSAL et s'applique donc à tous les objets. Elle effectue une copie profonde, la débride et renvoie la structure de données.

#!perl
use v5.10;

sub UNIVERSAL::TO_JSON {
    my( $self ) = shift;

    use Storable qw(dclone);
    use Data::Structure::Util qw(unbless);

    my $clone = unbless( dclone( $self ) );

    $clone;
    }

my $data = bless {
    foo => bless( [], 'Local::Array' ),
    quack => bless( {
        map { $_ => bless [$_, $_**2], 'Local::Array' } 
            grep { is_prime } 1 .. 10
        }, 'Local::Hash' ),
    }, 'Local::Hash';

use JSON::XS;
my $jsonner = JSON::XS->new->pretty->convert_blessed(1);
say $jsonner->encode( $data );

3 votes

Unbless est souvent utile, comme lorsque vous déboguez un état interne et que vous voulez vider un objet béni dans une boucle serrée... avec json::xs parce que Dumper est 100 fois plus lent, et json::xs ne videra pas un objet béni.... même s'il s'agit juste d'une hashref.

1 votes

En effet, JSON::XS est le seul endroit où je n'ai pas pu faire autrement. Merci, j'ai mis à jour ma réponse.

27voto

RandomMonkey Points 139

Si vous savez par quoi votre objet est soutenu, vous pouvez le faire sans utiliser de paquets.

Hachures

$obj = bless {}, 'Obj';
print ref $obj, "\n";
$obj = { %$obj };
print ref $obj, "\n";

Tableau

$obj = bless [], 'Obj';
print ref $obj , "\n";
$obj = [ @$obj ];
print ref $obj, "\n";

Scalaire

$obj = bless \$a, "Obj";
print ref $obj, "\n";
$obj = \${ $$obj };
print ref $obj, "\n";

2 votes

+1 parce que cela résout exactement mon problème, à savoir que je voulais juste accéder "temporairement" à la structure de données sous-jacente de l'objet (un Hash) pour facilement le Dump avec YAML::Tiny.

3 votes

Cela ne fonctionne que si seul le niveau supérieur est béni. Les valeurs de hachage ou les éléments de tableau peuvent eux-mêmes être des références bénies.

12voto

codeholic Points 2726

Acme::Malédiction :)

Mise à jour : Merci, Ivan ! J'ai confondu les modules. En fait, je voulais donner un lien vers Acme::Damn :))

P. S. Voir aussi Acme::Sneeze :)

P. P. S. Il n'a pas d'utilité réelle, c'est pourquoi il est Acme:: . Voir l'article de Brian.

1 votes

Mais ce module crée une copie de l'objet.

6 votes

Attribué à Mike Andrews dans alt.sysadmin.recovery : "Perl a déjà bénir et nous savons ce qu'il fait, n'est-ce pas ? Perl devrait également avoir frapper et nous savons aussi ce qu'il devrait faire. Si plus de langues avaient frapper mis en œuvre, les programmeurs restants seraient meilleurs que la moyenne actuelle".

-10voto

Miker Points 1
my $x = {}

bless $x, __PACKAGE__

# stripping the blessing
$x = lc $x;

un jeu d'enfant ;-)

Prograide.com

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.

Powered by:

X