Page 1 of 2

Acessing class constants dynamically

Posted: Sat Apr 28, 2007 5:02 am
by Ree
Everyone knows you can do this in PHP:

Code: Select all

$object = new Object();
$method = 'someMethod';
$object->$method(); //Object::someMethod() must be declared
Now I thought something like this would work as well:

Code: Select all

$constant = 'someConstant';
$value = Object::$constant; //Object::someConstant must be declared
But I get 'Fatal error: Access to undeclared static property: Object::$constant'.

Is there actually a way to access class constants dynamically?

Posted: Sat Apr 28, 2007 8:49 am
by bdlang
Works for me. How has 'someConstant' been declared? As a 'static' property?

Posted: Sat Apr 28, 2007 11:00 am
by Ree
No, as a constant:

Code: Select all

class someClass
{
  const someConstant = 'constant';
}

Posted: Sat Apr 28, 2007 12:10 pm
by Chris Corbyn
You should never need to do this because constants are fixed name and value... if you are accessing them dynamically then you should be using a variable. However:

Code: Select all

echo constant("Object::someConstant");
It's usually good practise to write constants with uppercase and underscore separated so they are easier to see in a sea of OO code :)

Posted: Sat Apr 28, 2007 12:42 pm
by Ree
d11wtq wrote:You should never need to do this because constants are fixed name and value...
If you expanded this statement and filled in the info related to the topic, it would look like this:
You should never need to read class constants because constants are fixed name and value...
:roll:
d11wtq wrote:if you are accessing them dynamically then you should be using a variable.
Why? Because of PHP limitation?
d11wtq wrote:It's usually good practise to write constants with uppercase and underscore separated so they are easier to see in a sea of OO code :)
In the original code they are named using the convention you described.

Posted: Sun Apr 29, 2007 5:23 am
by Ollie Saunders
Show us the code where you are using this "dynamic constant" and I guarantee you it can be rewritten without using such esoteric cack-handedness.

Posted: Sun Apr 29, 2007 6:23 am
by Chris Corbyn
ole wrote:Show us the code where you are using this "dynamic constant" and I guarantee you it can be rewritten without using such esoteric cack-handedness.
I agree... I can smell it from here ;)
Ree wrote:Why? Because of PHP limitation?
I'm not sure what all the eye rolling is about but I was geniunely just offering my advice.. it smells bad. Maybe if you explained what you're doing it would make more sense, btu right now it seems you should be using a variable/array. It's not a PHP limitation... the syntax you tried to use is the syntax PHP uses for static class fields; that's why you get an error. There's no limitation considering you can use the code I posted. Constants have the same semantics in all languages which use them...

Posted: Sun Apr 29, 2007 10:27 am
by Ree
ole wrote:Show us the code where you are using this "dynamic constant" and I guarantee you it can be rewritten without using such esoteric cack-handedness.
It's not a dynamic constant at all... We're definately not getting each other.

All right, one more example:

Code: Select all

<?php

class Request
{
  const GET = 'GET';
  const POST = 'POST';

  private $type;

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

  public function getType()
  {
    return $this->type;
  }  
}

$request = new Request(Request::GET);
echo $request->getType(); //GET
$request = new Request(Request::POST);
echo $request->getType(); //POST

$methodName = 'getType';
echo $request->$methodName(); //POST

$constantName = 'POST';
$request = new Request(Request::$constantName); //Fatal error

?>
You're trying to tell me I'm doing something wrong because I try to use class constants which is ridiculous. What I'm finding strange is that you can invoke methods dynamically, but cannot use constants in a similar fashion.

Posted: Sun Apr 29, 2007 10:53 am
by jmut
yes, your code looks kind of weird.
And they already told you how can dynamically call constants of classes.

Posted: Sun Apr 29, 2007 12:32 pm
by Ree
jmut wrote:yes, your code looks kind of weird.
It's not production code, it's just an example...

You guys really amaze me. The problem is so simple and yet you make it look so complicated. I'm really trying to figure out what you're so confused about that it 'smells' or 'looks weird' to you. You don't seem to think dynamic method invocation is wrong, but using constants the same way is? Again, that would be ridiculous IMO.

I'm wondering if this isn't related to the fact that maybe you don't see a possible use for this? Class constants are frequently used to store static internal class data which enables you as a client programmer to use this data without knowing its values at all or having to guess them (which could potentially cause problems). You just know 'what the data is' and not the value. It also allows the class creator to change the value at will (good for code generation as well).

Code: Select all

if ($request->getType() == Request::POST)
{
  //I don't care what the value of Request::POST is, I just know the request is of type 'POST'
}

if ($request->getType() == 'get')
{
  //This is a guess, the actual string returned may be in uppercase (or even change to something else if the class gets updated)
}
As for using constants dynamically, my case was based on construction of SQL queries. I needed to select certain users with certain roles and each role is represented by a boolean value of a corresponding column in the user table. The names of these columns are stored in constants of a class that provides ORM layer for this table. Dynamic use of constants is a perfect fit here since this allows me to have different methods to fetch corresponding types of users and refactor the actual fetching logic to a single method which removes code duplication. Each of the former methods passes the name of the corresponding constant (the role) and the latter method knows which class constant to use to do its job.

Anyway, thanks for pointing out the constant() method. Works fine, problem solved.

Posted: Sun Apr 29, 2007 1:54 pm
by Z3RO21
When you do this

Code: Select all

Request::$constantName
It looks for a static variable in the class named $constantName

that is why

Code: Select all

class test {
		static function testit() {
			echo 1;
		}
	}
	$func = 'testit()';
	test::$func;
does not work because there is no static variable $func... that is why your code looks weird and smells :roll:

Posted: Sun Apr 29, 2007 3:20 pm
by Chris Corbyn
Ree wrote:
jmut wrote:yes, your code looks kind of weird.
It's not production code, it's just an example...

You guys really amaze me. The problem is so simple and yet you make it look so complicated. I'm really trying to figure out what you're so confused about that it 'smells' or 'looks weird' to you. You don't seem to think dynamic method invocation is wrong, but using constants the same way is? Again, that would be ridiculous IMO.

I'm wondering if this isn't related to the fact that maybe you don't see a possible use for this? Class constants are frequently used to store static internal class data which enables you as a client programmer to use this data without knowing its values at all or having to guess them (which could potentially cause problems). You just know 'what the data is' and not the value. It also allows the class creator to change the value at will (good for code generation as well).

Code: Select all

if ($request->getType() == Request::POST)
{
  //I don't care what the value of Request::POST is, I just know the request is of type 'POST'
}

if ($request->getType() == 'get')
{
  //This is a guess, the actual string returned may be in uppercase (or even change to something else if the class gets updated)
}
As for using constants dynamically, my case was based on construction of SQL queries. I needed to select certain users with certain roles and each role is represented by a boolean value of a corresponding column in the user table. The names of these columns are stored in constants of a class that provides ORM layer for this table. Dynamic use of constants is a perfect fit here since this allows me to have different methods to fetch corresponding types of users and refactor the actual fetching logic to a single method which removes code duplication. Each of the former methods passes the name of the corresponding constant (the role) and the latter method knows which class constant to use to do its job.

Anyway, thanks for pointing out the constant() method. Works fine, problem solved.
That code looks good to me... you explicitly declare that you're looking for "POST" in Request. That's exactly the situation you'd use constants in :) I'm still not seeing why you would need to do that dynamically though... your code doesn't show this anywhere.

Posted: Sun Apr 29, 2007 3:22 pm
by Chris Corbyn
Is the ORM propel by any chance?

Posted: Sun Apr 29, 2007 4:51 pm
by Ollie Saunders
You don't seem to think dynamic method invocation is wrong, but using constants the same way is? Again, that would be ridiculous IMO.
You are so sure of yourself Ree I almost starting blinding agreeing with you. I didn't and that's because, mostly, I don't :) and for this reason I think you should pay attention. A disagreement is the genesis of realization (for somebody), providing an agreement can be reached ultimately and the debate's potential merits are not outweighed by the amount of time required to obtain them. With that in mind: -

A method represents a unit of behaviour. To choose the behaviour you wish to use dynamically improves flexibility. Simple. Despite this, calling method dynamically usually implies the use of __call() and is not always a good idea. There are issues of poor reflection. Documentation becomes more complicated and obtuse. Code readability and predictability usually suffers; this is in part redeemed by accepted practise e.g. design patterns.

The most legitimate use of a dynamic method invocation is direct delegation. Here the use is obvious and easy to explain and can be seen in certain implementations of the decorator pattern. Even with its drawbacks dynamic method calling, class instantiation and loading often provide advantages that are significant enough to justify their use.

Using a constant ensures that the correct value is being used and improves readability. I'm sure you are aware that if you attempt to access a constant that does not exist you will get an error. The dynamism makes no sense because where you had ensured integrity and predictability you are now throwing it out the window by creating the risk of attempting to access a constant that doesn't exist or accessing the wrong constant in the same way that using no constant at all puts you at risk of using incorrect data. In addition to this you can no longer see the name of the constant you are calling because that name is being generated dynamically. One could say that calling a constant in a dynamic way is negating the purpose of a constant altogether. Whilst there may be times where this certain combination of advantages and disadvantages makes more sense then any other I am willing to bet it is infrequent enough that I should question your use of it.

I would be interested to see your code Ree.

Posted: Sun Apr 29, 2007 8:43 pm
by dreamscape
d11wtq wrote:if you are accessing them dynamically then you should be using a variable.
Don't confuse access with value. There is a universe of difference between "dynamically" accessing something, and it having a dynamic value.

The mere notion that the constant() function is useless or bad practice is utterly ridiculous and unfounded.