views:

1775

answers:

4

In Perl, an object is just a reference to any of the basic Perl data types that has been blessed into a particular class. When you use the ref() function on an unblessed reference, you are told what data type the reference points to. However, when you call ref() on a blessed reference, you are returned the name of the package that reference has been blessed into.

I want to know the actual underlying type of the blessed reference. How can I determine this?

+6  A: 

Scalar::Util::reftype

Ryan Olson
+1  A: 

And my first thought on this was: "Objects in Perl are always hash refs, so what the hack?"

But, Scalar::Util::reftype is the answer. Thanks for putting the question here.

Here is a code snippet to prove this.. (in case it is of any use to anyone).

$> perl -e 'use strict; use warnings "all"; my $x = [1]; bless ($x, "ABC::Def"); use Data::Dumper; print Dumper $x; print ref($x) . "\n"; use Scalar::Util "reftype"; print reftype($x) . "\n"'`

Output:

$VAR1 = bless( [
                 1
               ], 'ABC::Def' );
ABC::Def
ARRAY
Jagmal
Objects are often implemented as hash references, but it's not a requirement. An object can be any reference type.
brian d foy
+3  A: 

You probably shouldn't do this. The underlying type of an object is an implementation detail you shouldn't mess with. Why would you want to know this?

Leon Timmermans
Agreed, and I knew somebody would make this comment. I really only needed this while trying to figure out a structure a module was creating so I could modify the module. I wanted to delete a particular key from any hashes in the structure because they contained a raw JPEG.
Ryan Olson
Later I discovered that I could use Data::Dumper::sortkeys to filter this data so Data::Dumper didn't produce megabytes of binary output.
Ryan Olson
+6  A: 

Scalar::Util::reftype() is the cleanest solution. The Scalar::Util module was added to the Perl core in version 5.7 but is available for older versions (5.004 or later) from CPAN.

You can also probe with UNIVERSAL::isa():

$x->isa('HASH')             # if $x is known to be an object
UNIVERSAL::isa($x, 'HASH')  # if $x might not be an object or reference

Obviously, you'd also have to check for ARRAY and SCALAR types. The UNIVERSAL module (which serves as the base class for all objects) has been part of the core since Perl 5.003.

Another way -- easy but a little dirty -- is to stringify the reference. Assuming that the class hasn't overloaded stringification you'll get back something resembling Class=HASH(0x1234ABCD), which you can parse to extract the underlying data type:

my $type = ($object =~ /=(.+)\(0x[0-9a-f]+\)$/i);
Michael Carman
You just want eval { $x->isa($type) }; If that's not an object, you get back false. If it's not the right type, you get false, and if it is the right type, you get true. :)
brian d foy