What is the equivalent of static methods in ColdFusion?
Asked Answered
G

3

13

In C#, I created static methods to help me perform simple operations. For example:

public static class StringHelper
{
    public static string Reverse(string input)
    {
        // reverse string
        return reversedInput;
    }
}

Then in a controller, I would call it by simply using:

StringHelper.Reverse(input);

Now I'm using ColdFusion with Model Glue, and I'd like to do the same thing. However, it seems like there's no concept of static methods in ColdFusion. If I create a CFC like this:

component StringHelper
{
    public string function Reverse(string input)
    {
        // reverse string
        return reversedInput;
    }
}

Can I only call this method by creating an instance of StringHelper in the controller, like this:

component Controller
{
    public void function Reverse()
    {
        var input = event.getValue("input");
        var stringHelper = new StringHelper();
        var reversedString = stringHelper.Reverse(input);
        event.setValue("reversedstring", reversedString);
    }
}

Or is there some place where I can put 'static' CFCs that the framework will create an instance of behind the scenes so I can use it as if it was static, kind of like how the helpers folder works?

Gardenia answered 2/9, 2011 at 19:21 Comment(3)
+1 for instance approach. Remember, ColdFusion is not Object oriented language at all. We make it look like OOP.Crape
You are using Model glue, so there will be most of the things in cfc only, and while using cfscript in cfc, we totally forget that ColdFusion is a scripting language as PHP and Classic ASP!Crape
Saying that ColdFusion is not object-oriented at all is just not true. It is not completely object-oriented (where everything is an object), but you can use it to program in an object-oriented way, using object-oriented concepts, OO design patterns, and more. It is object-oriented.Shady
S
17

Nope, you are correct, there is no concept of static methods in ColdFusion. I think most would solve this problem through the use a singleton utilities in the application scope that are create when the application starts. So in your App.cfc in onApplication start you might have:

<cfset application.StringHelper = createObject("component", "path.to.StringHelper") />

Then when you needed to call it from anywhere you would use:

<cfset reversedString = application.StringHelper.reverse(string) />

Yeah, it's not as clean as static methods. Maybe someday we could have something like them. But right now I think this is as close as you will get.

Shady answered 2/9, 2011 at 19:39 Comment(0)
I
6

One way to create statics in ColdFuison is to put the function or variable in the metadata of the object. Its not perfect but like a static you don't have to create an instance of the object to call them and they'll last until the server is restarted so they are quite fast after the first call.

Here's a quick snippet:

component name="Employee"
{
 public Employee function Init(){
  var metadata = getComponentMetaData("Employee"); 

  if(!structKeyExists(metadata,"myStaticVar")){

   lock name="metadata.myStaticVar" timeout="10"{
    metadata.myStaticVar = "Hello Static Variable."; 
   }
  }

  return this;
 }
}

More detail here: http://blog.bittersweetryan.com/2011/02/using-metadata-to-add-static-variables.html.

Iritis answered 2/9, 2011 at 19:52 Comment(1)
Is it possible to put a function in the metadata or only a variable?Schauer
E
3

CFML in year 2021+ supports STATIC methods and STATIC variables because now Adobe has implemented it in ColdFusion 2021 (Lucee supported it since 5.0). Here is a code example of a component named Cube.cfc and a index.cfm file which uses static methods that I used in this other SO thread. I'm adding this information here for completeness.

A CFC component named Cube.cfc

component displayname="Cube" accessors ="true" {
    // class properties
    property name="name" type="string";
    property name="model" type="string";
    property name="borderColor" type="string";
    property name="material" type="string";
    property name="dimension" type="struct";
    
    // set static varibales
    static { 
        private models =[ "model-a",  "model-b", "model-c" ];
        private modelNameMaterialMapping ={
            "model-a": "wood",
            "model-b": "steel",
            "model-c": "silver"
        };
        private modelNameDimensionsMapping ={
            "model-a": {"height": 100, "length": 100, "width": 100 },
            "model-b": {"height": 133, "length": 133, "width": 133 },
            "model-c": {"height": 85, "length": 85, "width": 85 }
        };

    };

 
    public any function init( 
        string name,
        string borderColor,
        string model

    ){
        setName( arguments.name );
        setBorderColor( arguments.borderColor );
        setModel( arguments.model );
        setMaterial(  static.getMaterialByModelName( arguments.model ) );
        setDimension( static.getDimensionByModelName( arguments.model ) );
        return this;
    }

   
    public static string function getMaterialByModelName( string modelName  ){

        return static.modelNameMaterialMapping[ arguments.modelName ];

    }

    public static struct function getDimensionByModelName( string modelName  ){

        return static.modelNameDimensionsMapping[ arguments.modelName ];

    }

    public static string function isValidModel( string model ){

        return static.models.contains( arguments.model );

    }


 }

And a index.cfm file that calls the static methods:

<cfscript>
 
    modelsForChecking=[
        "model-a",
        "model-k",
        "model-c",
        "model-z"
    ];

    // loop through model information without having any object instantiated by calling static functions
    for( model in modelsForChecking){
        if( Cube::isValidModel( model )){
            writeOutput("Cube ""#model#"" is valid.<br>");
            writeOutput( "Cube models ""#model#"" are made of ""#Cube::getMaterialByModelName( model )#"" and a dimension of ""#Cube::getDimensionByModelName( model ).width#x#Cube::getDimensionByModelName( model ).length#x#Cube::getDimensionByModelName( model ).height#""<br>");
        }else{
            writeOutput("Cube ""#model#"" is NOT a valid model.<br>");
        }
    }

    //intantiate a specific cube object with the name "CubeOne";
    writeOutput( "Instantiate an object with the component:<br>");
    CubeOne=new Cube("CubeOne", "white", "model-c" );
    
    // dump properties of the specific cube "CubeOne"
    writeDump( CubeOne );

    // get width with the accesso getter for property dimension for the cube named "CubeOne"
    writeOutput("""CubeOne"" has a width of #CubeOne.getDimension().width# <br>");
  
</cfscript>
Evyn answered 2/1, 2022 at 12:57 Comment(2)
How did you import Cube?Derron
This happens with CubeOne=new Cube("CubeOne", "white", "model-c" ); This is the new operator that will make the cfengine look for the Cube.cfc in the same directory. If Cube.cfc would be in a subfolder named "components", you would do a CubeOne=new components.Cube("CubeOne", "white", "model-c" );Evyn

© 2022 - 2024 — McMap. All rights reserved.