Page 1 of 1
Advantage of class constants in php5
Posted: Wed Nov 01, 2006 10:13 am
by matthijs
In Jason's book (Guide to PHP design patterns) he uses class constants (quite often). Like:
Code: Select all
<?php
class Bookmark {
const NEW_BOOKMARK = -1;
protected $id = Bookmark::NEW_BOOKMARK;
protected $conn;
public $url;
public $name;
public $description;
public $tag;
public $created;
public $updated;
const SELECT_BY_ID = 'select * from bookmark where id = ?';
public function __construct($id=false, $conn=false) {
$this->conn = ($conn) ? $conn : DB::conn();
if ($id) {
$rs = $this->conn->execute(
self::SELECT_BY_ID
,array((int)$id));
// ....
?>
Untill now I haven't seen the use of class constants a lot. In a couple of my php books they are merely mentioned but not used a lot.
So what do you think about the use of class constants? Is there a reason I don't see them a lot? Are there drawbacks/advantages of using them?
Posted: Wed Nov 01, 2006 11:10 am
by Chris Corbyn
Many people still just define global constants. Class constants are in essence the same thing.
If it were possible to make this construct in PHP it's the same behaviour:
Code: Select all
class MyClass
{
final public static $MY_CONSTANT = "xxx";
}
As with globally defined constants it's just a way of preventing anything overriding the value. Of course, apart from the case where you're in the class itself you can do the same sort of thing using private properties with public accessors. You could still modify the value internally though.
Posted: Wed Nov 01, 2006 11:28 am
by matthijs
Thanks for your answer. What they are/how they function is clear now.
So are there any (dis)advantages of using them?
Does using them make the code slower (something which I think I've read somewhere about constants being slow).
Is the fact that they are public a drawback? (in general or in this specific example)
Jason is not just an average coder I would think so there should be a good reason he uses them, shouldn't it?
Posted: Wed Nov 01, 2006 11:33 am
by John Cartwright
Some very helpful user comments found in
the manual
Posted: Wed Nov 01, 2006 12:07 pm
by matthijs
Thanks, indeed.
So if I understand it well:
- class constants are publicly visible: this could be a disadvantage because with private variables they would be better encapsulated
- class constants cannot be overriden: this could be a disadvantage because you might want to use a constant with the same name again in a child or other class? Maybe it's even possible the same name would be used again without you knowing it (if you use a large library of classes), and therefore create unexpected behavior.
Hmm, thinking about this, this could also be an advantage. Because in jason's example you will probably use const INSERT_SQL only once.
I think I don't see the point of using them at this point. Seems better to use private/public vars.
Posted: Wed Nov 01, 2006 12:21 pm
by Christopher
matthijs wrote:So if I understand it well:
- class constants are publicly visible: this could be a disadvantage because with private variables they would be better encapsulated
- class constants cannot be overriden: this could be a disadvantage because you might want to use a constant with the same name again in a child or other class? Maybe it's even possible the same name would be used again without you knowing it (if you use a large library of classes), and therefore create unexpected behavior.
I think of those differently:
- class constants are publicly visible but scoped to the class namespace -- therefore they do not clutter the global namespace and cannot clash with the same name declared elsewhere.
- they cannot be overridden because they are constants -- giving the benefit that constants provide by definition.
Posted: Wed Nov 01, 2006 12:22 pm
by Chris Corbyn
Being publically visible isn't an issue as I see it. Providing you can't modify the value externally, being able to see it is fine.
The point you make about the fact you cannot override the value is a bit backward. Constants are there for exactly that reason
And yeah, I agree, controlled access with private/protected properties and public accessors/mutators is probably a clean alternative with a bit more flexibility.
Posted: Wed Nov 01, 2006 12:54 pm
by alex.barylski
Class constants are cleaner...like already said they don't clutter the global namespace...
Although they are "typically" bound to a specific class and despite being public...could make for confusing code...
For instance consider a Circle class...the class likely requires the universal constant PI. I haven't used class constants in PHP much, but I imagine they are addressed using the static resolution operator like so: MyCircle::PI
You can now get that constant anywhere in your code using MyCircle::PI...
On second thought, this was a bad example because PI is pretty much snynomous with a circle...but I am sure there are other examples of *universal* constants which are not strictly bound to one object or another...
In which case using a define() might make sense.
Yes you could use MyUniversal class(es)
Code: Select all
MyDistanceConstants{
constant FEET_IN_MILE = 5280; // Guestimated
}
but including a class with tons of constants like that in your application probably doesn't make sense when you could just define a single constant like so:
Likewise, I am sure there are constants which are so loosely related to any kind of categorey or grouping they just make sense to remain a GLOBAL constant...
Cheers

Posted: Wed Nov 01, 2006 1:09 pm
by Chris Corbyn
This is a point yes. I have a whole class called "PCRE" which contains nothing than a list of constants:
Code: Select all
class PCRE
{
const URI = '/^[a-z]+://([a-z0-9-]+(?=\.))*[a-z0-9-]*?[a-z0-9](\?.*)$/i';
const DATE_UK = '~^\d{2}/\d{2}/\d{4}$~';
//etc etc
}
That's purely a namespacing reason, and I use them throughout in preg_..() functions and form validation etc
Code: Select all
$new_str = preg_replace(PCRE::URI, '<a href="$0">$0</a>', $old_str);
Posted: Wed Nov 01, 2006 1:17 pm
by matthijs
arborint wrote:- class constants are publicly visible but scoped to the class namespace -- therefore they do not clutter the global namespace and cannot clash with the same name declared elsewhere.
Ok, that makes a difference.
- they cannot be overridden because they are constants -- giving the benefit that constants provide by definition.
Well yes you are right of course. That is the function/benefit of constants. I was thinking more about situations in which you would try to redefine a constant which isn't possible and therefore create unexpected behavior. But if the constant is tied to the specific class (like bookmark::SOMECONSTANT) that won't be a problem I guess.
d11wtq wrote:Being publically visible isn't an issue as I see it. Providing you can't modify the value externally, being able to see it is fine.
Indeed
The point you make about the fact you cannot override the value is a bit backward. Constants are there for exactly that reason
Yes
Part of the reason I started this thread was that I hadn't seen using constants for something like a sql string (const SELECT_BY_ID = 'select * from bookmark where id = ?'; ). Maybe using a class constant for a sql statement like that, specific for that class does makes sense (can't be overriden and is therefore safer?).
Posted: Wed Nov 01, 2006 1:18 pm
by Chris Corbyn
Hmm.... namespacing... just got me thinking:
Code: Select all
<?php
class classmapper
{
const Test = 'My_Really_Long_Pear_Named_Class_Test';
}
class My_Really_Long_Pear_Named_Class_Test
{
public function __construct($x)
{
echo "My_Really_Long_Pear_Named_Class_Test constructed with $x as argument";
}
}
$o = new classmapper::Test('Blah');
Incidentally PHP refuses to parse it as I'd like but the following works:
Code: Select all
<?php
class classmapper
{
const Test = 'My_Really_Long_Pear_Named_Class_Test';
}
class My_Really_Long_Pear_Named_Class_Test
{
public function __construct($x)
{
echo "My_Really_Long_Pear_Named_Class_Test constructed with $x as argument";
}
}
$c = classmapper::Test;
$o = new $c('Blah');
If only that had worked as I'd hoped, it would make long winded class named easier to alias. There are other patterns for doing similar things though
EDIT | This works:
Code: Select all
<?php
class classmapper
{
public static $Test = 'My_Really_Long_Pear_Named_Class_Test';
}
class My_Really_Long_Pear_Named_Class_Test
{
public function __construct($x)
{
echo "My_Really_Long_Pear_Named_Class_Test constructed with $x as argument";
}
}
$o = new classmapper::$Test('Blah');
Posted: Wed Nov 01, 2006 1:30 pm
by Luke
Wow... Chris... that is really cool. Thank you for that little morsel! Some of my class names are getting pretty freakin' long, but that autoloader you wrote makes it so easy that it's worth the long names. Now you come up with this! I like that idea a LOT. LOL now if I use that method, I'll be naming my classes in a way that maps them to their location, and then on top of that creating a class that maps short names to long names that map to location... haha... programming is funny.

Posted: Wed Nov 01, 2006 3:12 pm
by matthijs
Indeed ..wow. Although I have a feeling I don't understand what's happening. The My_Really_Long_Pear_Named_Class_Test gets instantiated by a constant in the class classmapper?? Is this normal behavior?
... i've got a lot to learn..
Posted: Wed Nov 01, 2006 3:28 pm
by johno
I don't really want to hijack this thread but, what about
Code: Select all
class LibraryNamespace {
public static function instantiate($class) {
$args = func_get_args();
array_shift($args);
$reflection = new ReflectionClass($class);
return $reflection->newInstanceArgs($args);
}
}
class MyLibrary extends LibraryNamespace {
public static function AnAlias($title) {
return self::instantiate('So_Long_And_Thanks_For_All_The_Pears', $title);
}
}
class So_Long_And_Thanks_For_All_The_Pears {
public function __construct($title) {
echo "$title...works!";
}
}
$instance = MyLibrary::AnAlias('Hello');
I would be much better if __call() would work on static calls.
Posted: Wed Nov 01, 2006 3:32 pm
by Chris Corbyn
johno wrote:I would be much better if __call() would work on static calls.
I tried using __call() myself only to realise for the first time that it actually needs to be in object context

I've still yet to look at the reflection API properly
