Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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?)

share|improve this question
    
What version of php are you running... anonymous functions aren't available until 5.3. –  Orangepill Jul 2 '13 at 21:36
1  
Why so many closures? Seems unlikely all the logic is mutually exclusive? As such, consider subclassing and using polymorphism. –  Jason McCreary Jul 2 '13 at 21:36
    
@Orangepill, I'm using version 5.3. –  AMorrise Jul 2 '13 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. –  AMorrise Jul 2 '13 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 –  Mark Baker Jul 2 '13 at 21:49

3 Answers 3

up vote 3 down vote accepted

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
share|improve this answer
    
Implemented this and it worked great. –  AMorrise Jul 2 '13 at 21:54
    
Glad to hear :) –  Jari Jul 2 '13 at 21:54

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.

share|improve this answer
    
Thanks. This is very clear. –  AMorrise Jul 2 '13 at 21:46

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.

share|improve this answer
    
closures without use() don't need runtime information. –  bwoebi Jul 2 '13 at 21:38
1  
@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. –  Mike Brant Jul 2 '13 at 21:46
    
uh, let's call it static dependency injection. with prefilled variables in class –  bwoebi Jul 2 '13 at 21:48
    
And I'd bet the closure could be evaluated at compile time - just no use()? –  bwoebi Jul 2 '13 at 21:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.