2

I have a Json structure such as:

{
  "field1" => "one",
  "field2" => "two",
  ...
}

I'm using the perl Json module, and I can bless the Json returned to me into a class, such as: my $result = bless($json->{output},'MyClass')

So far so good - now I can create methods within MyClass.pm to return the values of field1, field2, etc. So it seems that via bless, I have direct access to set the properties of an object. But the danger is that I can also do things later in the code like: $result->{field1} = "anythingIwant";

...which is not so good. I know I could set the property like _field1 to indicate privacy but that doesn't prevent me from doing $result->{_field1} = "anythingIwant";

So is there a best practice approach in perl to handle this situation? In other words, it's super convenient to be able to bless Json output into a class to deserialize, but it also seems dangerous. I'm looking for the best of both worlds where I can still use bless but also prevent any client code from doing the anythingIwant scenario described above. I've looked into Moose, InsideOut etc but I'm not really sure if either of those would fit the bill or just introduce more complexity.

cdlane
  • 40,441
  • 5
  • 32
  • 81
user3653270
  • 166
  • 1
  • 8
  • The common explanation is that Perl asks you nicely to stay out of its yard. It doesn't stand at the gate with a shotgun. Even Moose typically uses blessed hashes under the hood. An Inside Out solution can be made more bullet proof, but at the cost of being more difficult to work into the typical fabric Perl's classes expect (Inheritance becomes more tricky, for example). – DavidO Aug 31 '15 at 02:14
  • have a look at http://www.perlmonks.org/?node_id=8251 – pcantalupo Aug 31 '15 at 02:19
  • Yes, there is: Don't do `$result->{field1} = "anythingIwant";`. I'm not joking. The best practice is simply not to access the internals of objects from outside the class. – ikegami Aug 31 '15 at 03:23
  • Are you really claiming that someone may write `$result->{field1} = "anythingIwant"` accidentally? Or are you asking how to protect your data from malicious attack? – Borodin Aug 31 '15 at 05:16
  • @pcantalupo - yes I had seen that link but thanks. It seems a bit overkill and not entirely bulletproof based on the comments. – user3653270 Aug 31 '15 at 12:52
  • 1
    @DavidO/ikegami - I'm beginning to accept that perl just does these types of things (oop) differently and really it's more about expectation management vis-a-vis objects. – user3653270 Aug 31 '15 at 12:59

1 Answers1

0

Yes, the answer is to bless a closure.

This can give you read-only access to the data (once you drop your original pointer) or both read and write access but only through your accessor method, never directly to the data:

package MyClass;

sub new {
    my $type = shift;
    my $class = ref $type || $type;

    my $self = shift;

    my $closure = sub {
              $self->{$_[0]};
        };

     return bless $closure, $class;
}

package main;

use strict;

my $json_snippet = {
  "field1" => "one",
  "field2" => "two",
};

my $object = MyClass->new($json_snippet);

print($object->("field2"), "\n");

1;

Here's an introduction to Objects with Private Variables

cdlane
  • 40,441
  • 5
  • 32
  • 81