http://qs321.pair.com?node_id=58302

joecamel has asked for the wisdom of the Perl Monks concerning the following question:

I have a large group of modules (classes) whose names are stored in a database. I would like to be able to construct any of the objects dynamically. Here is the basic function I have created:

# Returns the object for a given widget ID sub get_widget { my $widgetID = shift; my $className = get_widget_class_name($carrierID); my $fullClass = 'SuperWidget::Widget::' . $className; my $widget = new $fullClass ($widgetID); return $widget; }

It worked great for a while, but now it's giving me the following error:

syntax error at file, line #, near "$fullClass ("

I followed the basic constructor method call format from Damian Conway's Object-Oriented Perl (incredible book, BTW), so I'm not sure why it isn't working, especially since it worked earlier. I have checked that both widgetID and widgetClassName are coming back as valid values. I am "use"ing all of the potential class names, and each one's package is named correctly, like:

package SuperWidget::Widget::SpecificWidget;<p>

The subroutine works correctly when I substitute $fullClass for a literal string in the constructor call.

Does anyone know what I am possibly doing wrong?

Thanks in advance for the help! :)

joecamel

Replies are listed 'Best First'.
Re: How to a construct objects with variables as class names?
by Adam (Vicar) on Feb 14, 2001 at 11:16 UTC
    The problem looks to be with your call to new(). When you don't have new() defined in the current name space, and you call
    new class, @args
    Perl guesses that class::new() is defined and tries that. But you havn't given it a class name, you've given it a variable. You might try
    $class->new( @args )
    I've had some luck with that in the past. By the way, 'pointy' is the preferable way to invoke methods on objects and classes, as it eliminates the uncertainty of who's method is being called. Also, make sure that $class has been required, and actually is compiled.
      Thanks Adam,

      I changed the method to the following, which worked perfectly:

      my $fullClass = "SuperWidget::Widget::" . $className; my $widget = $fullClass->new($widgetID);
      I normally use the -> operator for method calls, but figured the only way to dynamically name an object was with the new class (@args) format.

      joecamel

Re: How to a construct objects with variables as class names?
by MeowChow (Vicar) on Feb 14, 2001 at 12:00 UTC
    What you are trying to do is similar in principle to variable variables, though not nearly as insecure. Still, who knows what badness may result from instantiating an object into a subclass that you're not expecting. For that reason, you may want to create a hash of accepted widget subclasses, and modify your instantiation like so:
    my $widget = $fullClass->new($widgetID) if exists $OK_CLASSES{$fullC +lass};
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
      Good suggestion, though I'm actually checking for that in the sub that gets the classname from the database. If the query returns nothing, it errors out. Defining the names in the database is at least as reliable as putting them in an array, I think. Since I use all of the widgets at the top, that should catch any potential mistakes in the db.

      I'm curious to know if there is a way to get around useing them though -- I would ideally like to be able to add widgets by simply:

      1) add the class module to the directory
      2) add the class name to the database

      The above sub resides in a module running on mod_perl, so every time I change it, I have to stop and restart the http server, which I'd rather not have to do. Of course, I realize there are some stability problems that could arise when doing this sort of thing.

      joecamel

        Sure, this is secure so long as the table you're checking the values against is comprised of data that only you (not your users) can manipulate, and it sounds like this is what you're doing.

        Regarding your second question, you may want to have a look at Related question: loading modules at run time. You will also want to do something like:

        eval "require $pkg";
        because of the differences in the way require EXPR works from require BAREWORD.

           MeowChow                                   
                       s aamecha.s a..a\u$&owag.print