14

Given 3 variables:

String a = 'Apple';
String b = 'Orange';
String varname = 'a';

Is there a way that I can use varname as a link to the variable a in my code such that the following would evaluate to true?:

if (Var(varname)=='Apple')

I know that there are ways to do it in some scripting languages such as PHP but have been unable to find any mention of this in Apex searching the web.

The PHP equivalent of what I'm after appears to be $($varname).

1
  • There's nothing out of the box, but there is a solution that should approach what you're looking for.
    – sfdcfox
    Jan 17, 2014 at 16:48

5 Answers 5

19

No. Apex is a compiled language, what you're describing are variable variables typically found in languages that are parsed (interpreted) at runtime (let's not dig into opcodes, Zend's virtual machine, Facebook's HipHop etc).

Apex can be pretty flexible when executing queries from strings (but compiled query performs faster) and there are ways to do something like SELECT * FROM Account and access all fields on the object.

Search the documentation for "dynamic Apex" but the bottom line is that the code has to be compiled before it's executed. Maybe if you'd write more about your requirements (like accessing all name-value parts in URL?) we'd be able to assist more.

You can also try to use the API to fire off ExecuteAnonymous calls (code snippets that are run and discarded, they won't be saved as new class for example) but that's getting bit hardcore...

There's Type class that lets you instantiate variables in dynamic way - but you still have to specify the variable name at compile-time. There's instanceof operator, interfaces, How to invoke a method of an apex class at run time... lots of options to "do it right".


Edit: I forgot about 1 more hack: JSON.deserialize* methods. They come in few flavours... But even then you have to dump them into "some named variable" and (in the example without expected type definition) access as the Map example from other answers. So at best you'd be getting a map with many interesting properties. If you're interested in bit more complex example of casting - check out https://stackoverflow.com/questions/3122038/how-do-i-integrate-salesforce-with-google-maps, I'm pretty happy how that one turned out.

3
  • nice comprehensive brainstorm covering all avenues Jan 17, 2014 at 13:26
  • 6
    @user320 reminds me the glorious days of #define true false /* Happy debugging suckers */ ;)
    – eyescream
    Jan 17, 2014 at 13:59
  • You forgot about object maps...
    – sfdcfox
    Jan 17, 2014 at 16:47
18

I do not believe this is directly possible, however using a map of the variables to a String you would be able to check for a specific variable name and produce the effect shown in your example.

Map<String,String> varNameToValueMap = new Map<String,String>();
varNameToValueMap.put('a','Apple');
varNameToValueMap.put('b','Orange');

String varname = 'a';

Then you could execute the if statement shown in your question as follows.

if(varNameToValueMap.get(varname) == 'Apple')
1
  • This is exactly what the OP is asking for, great answer, as much as the accepted answer is technically correct, this actually solves the OPs problem. @Venko original question actually uses a simialr syntax (just without the get and put methods). Only issue I can think of for lack of trying would be to assign values directly from visualforce. Nov 1, 2019 at 21:50
12

You can do this with a Map type. It's the Apex equivalent of a PHP associative array.

String varname = 'a';

Map<String,String> vars = new Map<String,String>{
    'a' => 'Apple',
    'b' => 'Orange',
};

if (vars.get(varname) == 'Apple') {
    //
}
2
  • The PHP equivalent of what I'm after appears to be $($varname).
    – Venko
    Jan 17, 2014 at 12:20
  • 2
    Variable variables are bad enough practise in PHP and not supported in Apex @Venko Jan 17, 2014 at 12:25
8

Dynamic variables do not exist in Apex Code, because it is a "strongly typed" language. Languages such as PHP are "loosely typed" languages, which means that they are partly compiled, and then interpreted as a scripting language.

However, if you truly wanted to emulate dynamic variables, you could use the following class:

global class Vars {
    static map<object, map<object, object>> values = new map<object, map<object, object>>();
    global static object get(object scope, object key) {
        if(!values.containskey(scope)) {
            return null;
        }
        return values.get(scope).get(key);
    }
    global static void set(object scope, object key, object value) {
        if(!values.containskey(scope)) {
            values.put(scope, new map<object, object>());
        }
        values.get(scope).put(key, value);
    }
    global static boolean isset(object scope, object key) {
        return values.containskey(scope) && values.get(scope).containsKey(key);
    }
    global static void remove(object scope, object key) {
        if(isset(scope, key)) {
            values.get(scope).remove(key);
        }
        if(values.get(scope) != null && values.get(scope).isEmpty()) {
            values.remove(scope);
        }
    }
    global static void remove(object scope) {
        values.remove(scope);
    }
    global static boolean isempty(object scope, object key) {
        return !isset(scope, key) || values.get(scope).get(key) == null || String.valueOf(values.get(scope).get(key)) == '';
    }
    global static boolean isequal(object scope, object key, object value) {
        return !isempty(scope, key) && get(scope, key).equals(value);
    }
}

Usage

// Set a global variable
vars.set(null, "myvar", 12345);
// Set a local variable
vars.set(this, "myvar", 12345);
// Get a global variable; must cast to get to a primitive type
integer a12345 = (integer)vars.get(null, "myvar");
// Get a local variable; must cast to get to a primitive type
integer a12345 = (integer)vars.get(this, "myvar");
// See if a value is as expected
if(vars.isequal(this, "myvar", 12345)) { ... }
// See if a value has been set
if(vars.isset(this, "myvar")) { ... }
// See if a value is blank or not
if(vars.isempty(this, "myvar")) { ... }
// Store a complex object
vars.set(null, "myvar", new map<string, account>());
// Access a complex object; cast is required
((map<string, account>)vars.get(null, "myvar")).put("some account", new Account());
// remove a variable from a scope
vars.remove(null, "myvar");
// remove all variables in a scope
vars.remove(this);

As you can see, there are some subtleties involved to make this work, such as requiring casts to concrete types, but this system is fuctionally similiar to dynamic variables. Note that casting is required for most operations, such as accessing a specific method or using any comparison operator other than ==, !=, ===, or !== (such as <, >, etc). Also, you can't store references to functions, because the language doesn't allow that, and you can't access a function without casting. For example, the following code won't work: vars.get(null, "myvar").put("some account", new account());.

Feel free to experiment with this code and see what you can do. In the end, it may be more trouble than it's worth (I think so), but this should give you some idea of the potential capabilities of the language. Even though dynamic variables aren't directly supported, you can achieve some degree of freedom. Also note that, unlike a regular dynamic variable situation, you can use any value as a key, including dates, numbers, complex objects, etc.

0

I came across a nice solution if you want to grab class variables dynamically along with their values (inspired by Daveed's answer here):

public class MyWrapper {
  public static final String VAR_NAME = 'name';

  public String name;
  public Integer count;
  public Account myAcct;

  public MyWrapper(){}

  // Returns Map<key, value> only on populated items
  public Map<String, Object> getClassMap() {
    return (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(this, true));
  }
}

public void sampleMethod() {
  MyWrapper wrapper = new MyWrapper();
  wrapper.name = 'Bob';
  wrapper.count = 2;
  wrapper.myAcct = new Account(Name = 'Bob Inc.');

  Map<String, Object> wrapperMap = wrapper.getClassMap();

  // Dynamic key/value access to MyWrapper variables
  for (String key : wrapperMap.keySet()) {
    Object value = wrapperMap.get(key);
    System.debug('MyWrapper class: ' + key + ' => ' + value);
  }

  System.debug('Let us just get the wrapper name: ' + wrapperMap.get(MyWrapper.VAR_NAME));
}


1
  • A more robust solution can be found here Aug 19, 2019 at 7:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .