Utility Functions For Classes
On the heels of last Friday’s article on Utility Functions For Objects, today’s article will show a few utility functions for the Class class. In case you’re not familiar with it, Class represents a class like you would write and is useful main for more dynamic programming where you want to instantiate a class based on a variable (eg. var c:Class) rather than a constant (eg. BitmapData). So how do you get a Class variable? The Flash API provides some ways to go about it and I’ll provide some ways to make that more convenient.
The most natural way for most people to think about getting Class variables is by a String class name. There is indeed such a function in the Flash API: flash.utils.getDefinitionByName. However, using it is less than friendly. It can throw a ReferenceError if the class does not exist and many programmers don’t like to use try/catch blocks due to the large amount of typing. So this function will do the try/catch work for you and return null instead, which was probably a more sensible and consistent behavior anyhow. getDefinitionByName also returns an Object rather than a Class and is therefore less type safe and less readable. The getClassByName utility function will do this cast for you and deal with the possible TypeError in the case that the Object is not really a Class.
/** * Get a class by its fully-qualified name * @param className Fully-qualified name of the class * @return The class with the given name or null if none exists * @author Jackson Dunstan */ public static function getClassByName(className:String): Class { try { return Class(getDefinitionByName(className)); } catch (refErr:ReferenceError) { return null; } catch (typeErr:TypeError) { return null; } return null; }
Today’s article is only covering three utility functions and the next two are related. Both of these answer the question “how do I get the Class of an Object?” Since we know how to get a Class from a String name from the above getClassByName function, all that we need is the name of the Object‘s class in order to get it. Thankfully there is a flash.utils.getQualifiedClassName function available to us, so the utility function is seemingly straightforward to implement. However, an issue arises when dealing with multiple ApplicationDomains. The getQualifiedClassName function only checks the current ApplicationDomain for definitions and therefore we have issues with child domains. One common child domain is the domain SWFs are loaded into and one common reason use for this getClass utility function is to get a class of a DisplayObject defined in a SWF’s library. So we can fall back on a sister function– getDisplayObjectClass— in case we fail with getQualifiedClassName. This can, of course, be called directly as well.
/** * Get the class of an object * @param obj Object to get the class of * @return The class of the given object or null if the class cannot be * determined * @author Jackson Dunstan */ public static function getClass(obj:Object): Class { if (obj == null) { return null; } try { var className:String = getQualifiedClassName(obj); var ret:Class = Class(getDefinitionByName(className)); if (ret == null && obj is DisplayObject) { ret = getDisplayObjectClass(DisplayObject(obj)); } return ret; } catch (refErr:ReferenceError) { return null; } catch (typeErr:TypeError) { return null; } return null; } /** * Get the class of a display object * @param obj Object to get the class of * @return The class of the given object or null if the class cannot be * determined * @author Jackson Dunstan */ public static function getDisplayObjectClass(obj:DisplayObject): Class { try { return Class(obj.loaderInfo.applicationDomain.getDefinition(getQualifiedClassName(obj))); } catch (refErr:ReferenceError) { return null; } catch (typeErr:TypeError) { return null; } return null; }
I’ve found these utility functions are quite useful with more dynamic programming. I hope you find the same.
#1 by Piergiorgio Niero on December 7th, 2009 ·
Yep, AS3 lacks a good set of functions to get information over classes and reflect object.
recently I experimented a bit on reflection and it has been very frustrating not to be able to create a flexible factory without workarounding as3 limitations.
I wrote a post ( http://twurl.nl/omcds2 ) and opened a feature request ( http://twurl.nl/hh84o7 ) to make things easier in next future, let’s hope adobe will reflect on flash :)
my 2 cents,
pigiuz
#2 by jackson on December 7th, 2009 ·
I too came to the same solution involving a switch, except I went all the way up to 20 parameters. I guess that would be another Class-related utility function.
#3 by dVyper on December 9th, 2009 ·
Nice functions :-)
Just a note that it doesn’t seem like you need the “var c:Class;” line in your getClassByName function.
#4 by jackson on December 9th, 2009 ·
Good catch! It must have been left over from a previous implementation. I’ve removed it and updated the article. Thanks!
#5 by NoriSte on December 30th, 2009 ·
I use this my own simple function
But the your one is longer than mine; I’m here for asking you if I’m loosing anything using my poor-code function… perhaps is slower in performance? (but I haven’t tested, these are only assumptions) or my getClass has some faults? I’ve been used it for a long time and it has caused me no one problem until now :-)
#6 by jackson on December 30th, 2009 ·
First of all, mine is longer than yours partly because mine includes more features. The try/catch block alone adds several lines, as does the null check. The purpose of these is to catch errors and return null rather than propagating them. I also fall back to getDisplayObjectClass. Other than that, my version is quite short. I’m not striving for performance in these functions as you would typically not use them in a performance-critical area of code. Instead, you would cache their result.
Other than that, your constructor field version does seem to work. I’m puzzled though- what is the purpose of your check against [class MethodClosure]? Is MethodClosure a class you’ve written and would like to treat specially?
#7 by NoriSte on January 4th, 2010 ·
See @ this code in the document class:
var movieClip : MovieClip = new MovieClip();
var obj : Object = {};
obj.myFunction = function(){};
trace( Object( myFunction ).constructor ); //myFunction is a function of the document class
trace( Object( movieClip.play ).constructor );
trace( Object( obj.myFunction ).constructor );
Flash traces this:
[class MethodClosure]
[class MethodClosure]
[class Function]