2

I'm attempting to make an achievement system for a memorization website ("You memorized 50 cards," etc.), and the method I'm trying to use is an array of anonymous functions:

class AchievementController extends Controller
{
    private static $rules = array(
        'card'=>array(
            1=>function() {
                //do check for achievement
            },
            2=>function() {
                //do check for achievement
            }
         ),
         'set'=>array(
            5=>function() {
                //do check for achievement
            },
            6=>function() {
                //do check for achievement
            },
         )
    );
    //...
}

The idea is that certain types of rules for achievements will be checked at certain times, i.e. when you learn a new card, the card subset will be checked. I had hoped to use a foreach loop like this:

foreach(self::$rules[$type] as $rule)
{
    $rule();
}

However, when I try to declare the $rules array, I get this error:

PHP Parse error: syntax error, unexpected 'function' (T_FUNCTION) in /.../controllers/achievement.php on line 24

If I declare $rules inside a function (NOT static), it works just fine. I can't put it inside a constructor, because this class is being used statically, so no constructor will be called.

My question is, is it possible for me to do this in a static array? Or ought I just to do something else?

(Extra question: Is there a better way than this to do achievements?)

9
  • What version of php are you running... anonymous functions aren't available until 5.3. Commented Jul 2, 2013 at 21:36
  • 1
    Why so many closures? Seems unlikely all the logic is mutually exclusive? As such, consider subclassing and using polymorphism. Commented Jul 2, 2013 at 21:36
  • @Orangepill, I'm using version 5.3. Commented Jul 2, 2013 at 21:45
  • @JasonMcCreary, these achievements are all unique, (learned 10 cards, learned 50 cards), so I was planning to have other functions be reused inside these anonymous ones. Commented Jul 2, 2013 at 21:46
  • @Alex - I wasn't being sarcastic, I was being serious... while I don't believe that statics are an antipattern, I do believe that they can cause a lot of problems that can be eliminated by a simple instantiation Commented Jul 2, 2013 at 21:49

3 Answers 3

4

No way you can pre-declare them (anonymous functions) in a class. You can do it inside a class method though:

class AchievementController extends Controller {
  public static $rules = array() ;

  public static function setup(){
    self::$rules = array(
      0 => function(){
        echo "One-statement array" ;
      }) ;

    //OR


    self::$rules[0] = function(){
      //Echo "ASD" ;
    } ;
    self::$rules[1] = function(){
      //Echo "ASD2" ;
    }
  }
}

AchievementController::setup() ; //Just calling pseudo-constructor for static class
Sign up to request clarification or add additional context in comments.

Comments

1

Current PHP grammar only supports primitive types, arrays and compile time constants in predefined class variables. For an exact list of what it supports see also http://lxr.php.net/xref/PHP_TRUNK/Zend/zend_language_parser.y#945.

What you can do is maybe declaring your class' methods as private and the use __callStatic as a wrapper. If the static property is then not yet set, set them. And then call the class method.

Or just make some setup at the beginning. like @Jari suggested.

Comments

1

It is not possible to do in a static array like this. The property declaration must be constant as noted in PHP docs here (http://www.php.net/manual/en/language.oop5.properties.php).

This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.

What you could perhaps do is have the function names defined statically, i.e.:

private static $rules = array(
    'card'=>array('function1', 'function2'),
    'set'=>array('function3', 'function4')
);

And then you could simply use these references to call NAMED method calls:

public static function function1 () {
     // some logic
}

public static function function2 () {
    // some logic
}

However, this whole thing seems very clunky. Seems to me you might want to have an achievement interface which defines certain methods (i.e. checkAchievements) and then have concrete implementing classes for cards, sets, etc.

3 Comments

@bwoebi The closure cannot be evaluated at compile time. It is not a constant value. If the closure did indeed do something trivial like function() { return true; } which is constant-like than there would be no need for the closure at all.
uh, let's call it static dependency injection. with prefilled variables in class
And I'd bet the closure could be evaluated at compile time - just no use()?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.