0

I'm rather new in PHP and it turns out that I'm not able to find a solution for the following problem:

I have a simple class like this:

class User{

  private $name;

  function __construct($name){
    $this->name = $name;
  }
}

All I want to do is to define a static instance of it, like one of these:

public const UNKNOWN_USER = new User("unknown);

so that I can use this as a dummy everywhere, e.g.:

public static login($name){
  if( /* userdoesnotexist */ ){
    return UNKNOWN_USER;
  }
}

and check for it - of course:

if( login($name) == UNKNOWN_USER){
  /* I don't know you! */
}

I've tried the following:

$UNKNOWN_USER = new User("unknown");
/* $UNKNOWN_USER not available in class-methods */

define(UNKNOWN_USER, new User("unknown"));
/* not allowed */

class User{
  const UNKNOWN_USER = new User("unknown");
  /* "new" leads to a syntax error */
}
MyPasswordIsLasercats
  • 1,610
  • 15
  • 24
  • 1
    Have a look at the [null object pattern](http://en.wikipedia.org/wiki/Null_Object_pattern) as well, as that kind of seems to be what you are trying to achieve. – Decent Dabbler Dec 08 '13 at 22:26
  • yes like @fireeyedboy noted a null object or just `null` would probably be a better return value. Because: What if there is a real user with name "unknown" and what happens if you call the login method of user "unknown"? – bitWorking Dec 08 '13 at 22:32
  • The null object pattern is indeed an interesting pattern which I do not know and the demur because of the the real user with the name "unknown" is definetly true. But I can deal with that design flaw in favour of better code-readability. I hate `null` as a return value and the login method is static , so it won't be called on the unknown_user :) – MyPasswordIsLasercats Dec 08 '13 at 22:41

3 Answers3

2

For constants only scalar values are allowed (float, int, string, bool, NULL). But you can set your UNKNOWN-insatnce to a static class variable

class User{
  public static $unknown_user = NULL;
  ...
}

User::$unknown_user = new User("unknown");

and then user User::$unknown_user instead of UNKNOWN_USER.

Jörg Mäder
  • 677
  • 4
  • 13
0

You cannot use const for anything else then scalar types. That excludes any objects. What you are trying to achive here is to make an object immutable. You can do this in many ways though they are nither simple nor straightforward. Take a look at the Builder pattern for instance. Another way would be to make the object lockable. But all of the safe methods to achieve this require some coding on your part.

The simplest lockable pattern for your example, that I can think of:

class User{

    private $name;

    private $is_locked = false;

    function __construct($name){
        $this->setName($name);
    }

    public function lock() {
        $this->is_locked = true;
    }

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        if ( $this->is_locked ) {
            throw new Exception("The object is locked");
        }
        $this->name = $name;
    }
}

Now you can do:

$user1 = new User("John");
$user1->setName("Johnny");

but after you lock the object, you can't manipulate it anymore:

$user1->lock();
$user1->setName("Big John"); // Exception thrown
Maciej Sz
  • 11,151
  • 7
  • 40
  • 56
0

You can do that like this:

<?php 
//Normal UnknownUser singleton pattern
class UnknownUser {
    private static $instance;

    //define properties
    public $myproperty = "hiho123";        

    private function __construct() {

    }

    public static function getInstance() {
       if(empty($instance)) {
          self::instance = new UnknownUser();
       }
       return self::instance;
    }

    //Make the class constant
    function __set($name, $value) {
        throw new Exception("Can't set property: " . __CLASS__ . "->$name");
    }
}

You can call the UnknownUser, like this:

$unknownUser = UnknownUser::getInstance();

And this make this class global and constant, can not be modified, because the magic method __set is activated to disable editing the properties.

Tomás
  • 3,501
  • 3
  • 21
  • 38