Why does the following code give me an exception saying that my constant isn't defined
MyClass::myFunction(MyClass::MY_CONST); // THIS GIVES THE ERROR
// This is the class..
class MyClass {
const MY_CONST = 'BLA';
public static function myFunction($key) {
if (!defined($key)) {
throw new Exception("$key is not defined as a constant");
}
}
}
I've tried with
if (!defined($key)) {}
if (!defined(self::$key)) {}
if (!defined(__CLASS__ . $key)) {}
You have to pass it as a string:
public static function myFunction($key) {
if (!defined('self::'.$key)) {
throw new Exception("$key is not defined as a constant");
}
}
MyClass::myFunction('MY_CONST');
As Daniele D points out, for starts you're calling it with the value of the constant, not its name.
And defined needs a different syntax for the parameter when checking class constants, rather than defined constants. It should be
if (!defined('self::' . $key)) {
You need to pass the entire class name and constant as a string.
Like:
MyClass::myFunction('MyClass::MY_CONST');
Related
I need to access a constant that belongs to a class, but instead of writing the class' name explicitly, I want to retrieve it from the object directly. The object is a property of another object.
$this->fetcher::BASE_URL
This statement produces the error syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
Here's an ugly work-around....
<?php
class simpleClass {
public function __construct() {
$this->fetcher = new simpleClass2();
}
public function printBaseURL() {
$fetcher = $this->fetcher;
print 'Base URL: ' . $fetcher::BaseUrl;
}
}
class simpleClass2 {
const BaseUrl = 'one';
}
$simpleClass = new simpleClass();
$simpleClass->printBaseURL();
You could use a function to return the constant
class MyClass
{
function getConstant() {
return self::CONSTANT . "\n";
}
}
Then call that function
$class = new MyClass();
$class->getConstant();
Or simply call the constant
MyClass::CONSTANT;
You can find more information about accessing constants within classes here. Look at the "user contributed notes", very good examples with explanation there.
I have trouble accessing a constant of a class via the object operator(->).
I have these 2 classes:
class withConstant {
const MY_CONSTANT = 5;
}
class usingConstant {
public $class = null;
function __construct() {
$this->class = new withConstant();
}
}
When I do this:
$myClass = new usingConstant();
echo $myClass->class::MY_CONSTANT;
I get an error Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM). However, I can get around it with this:
$myClass = new usingConstant();
$myClass = &$myClass->class;
echo $myClass::MY_CONSTANT;
I prefer to access the constant without assigning the member variable to another variable first.
This is the closest I can come to what you're actually after achieving unfortunately:
echo constant(get_class($myClass->class).'::MY_CONSTANT');
Note that this is incredibly inefficient, since it looks up the class to determine it's name, then looks it up again to reference the constant.
You can make a getter function in withConstant and call that.
class withConstant {
const MY_CONSTANT = 5;
function getConstant(){
return self::MY_CONSTANT;
}
}
Then you can call that function:
$myClass = new usingConstant();
echo $myClass->class->getConstant();
My class looks similar to this:
class Foo {
const UNKNOWN = 2;
public function doStuff($var) {
if($var==UNKNOWN) {
echo "Unknown state";
return;
}
// other stuff
}
}
However, I'm getting this error in doStuff():
Use of undefined constant UNKNOWN - assumed 'UNKNOWN'
What am I doing wrong? Can't I define custom constants?
You must use self:: or the class name when accessing the constant in your class:
if($var == self::UNKNOWN) {
echo "Unknown state";
return;
}
Documentation has the example of defining the constants in the PHP class.
self:: will help
class Constants
{
//define('MIN_VALUE', '0.0'); WRONG - Works OUTSIDE of a class definition.
//define('MAX_VALUE', '1.0'); WRONG - Works OUTSIDE of a class definition.
const MIN_VALUE = 0.0; // RIGHT - Works INSIDE of a class definition.
const MAX_VALUE = 1.0; // RIGHT - Works INSIDE of a class definition.
public static function getMinValue()
{
return self::MIN_VALUE;
}
public static function getMaxValue()
{
return self::MAX_VALUE;
}
}
for using every dynamic field in php you must call $this->field
and for using every static field and const in php you must call self::field
example:
class ApiController {
public static $static= "";
public $dynamic= "";
public function __construct() {
$a=$this->$dynamic;
$b=self::$static;
}
}
I'd like to do something like this:
public static function createDynamic(){
$mydynamicvar = 'module';
self::$mydynamicvar = $value;
}
and be able to access the property from within the class with
$value = self::$module;
I don't know exactly why you would want to do this, but this works. You have to access the dynamic 'variables' like a function because there is no __getStatic() magic method in PHP yet.
class myclass{
static $myvariablearray = array();
public static function createDynamic($variable, $value){
self::$myvariablearray[$variable] = $value;
}
public static function __callstatic($name, $arguments){
return self::$myvariablearray[$name];
}
}
myclass::createDynamic('module', 'test');
echo myclass::module();
static variables must be part of the class definition, so you can't create them dynamically. Not even with Reflection:
chuck at manchuck dot com 2 years ago
It is important to note that calling ReflectionClass::setStaticPropertyValue will not allow you to add new static properties to a class.
But this looks very much like a XY Problem. You probably don't really want to add static properties to a PHP class at runtime; you have some use case that could be fulfilled also that way. Or that way would be the fastest way, were it available, to fulfill some use case. There well might be other ways.
Actually the use cases below are yet again possible solutions to some higher level problem. It might be worth it to reexamine the high level problem and refactor/rethink it in different terms, maybe skipping the need of meddling with static properties altogether.
I want a dictionary of properties inside my class.
trait HasDictionary {
private static $keyValueDictionary = [ ];
public static function propget($name) {
if (!array_key_exists($name, static::$keyValueDictionary) {
return null;
}
return static::$keyValueDictionary[$name];
}
public static function propset($name, $value) {
if (array_key_exists($name, static::$keyValueDictionary) {
$prev = static::$keyValueDictionary[$name];
} else {
$prev = null;
}
static::$keyValueDictionary[$name] = $value;
return $prev;
}
}
class MyClass
{
use Traits\HasDictionary;
...$a = self::propget('something');
self::propset('something', 'some value');
}
I want to associate some values to a class, or: I want a dictionary of properties inside some one else's class.
This actually happened to me and I found this question while investigating ways of doing it. I needed to see, in point B of my workflow, in which point ("A") a given class had been defined, and by what other part of code. In the end I stored that information into an array fed by my autoloader, and ended up being able to also store the debug_backtrace() at the moment of class first loading.
// Solution: store values somewhere else that you control.
class ClassPropertySingletonMap {
use Traits\HasDictionary; // same as before
public static function setClassProp($className, $prop, $value) {
return self::propset("{$className}::{$prop}", $value);
}
public static function getClassProp($className, $prop) {
return self::propget("{$className}::{$prop}");
}
}
// Instead of
// $a = SomeClass::$someName;
// SomeClass::$someName = $b;
// we'll use
// $a = ClassPropertySingletonMap::getClassProp('SomeClass','someName');
// ClassPropertySingletonMap::setClassProp('SomeClass','someName', $b);
I want to change, not create, an existing property of a class.
// Use Reflection. The property is assumed private, for were it public
// you could do it as Class::$property = $whatever;
function setPrivateStaticProperty($class, $property, $value) {
$reflector = new \ReflectionClass($class);
$reflector->getProperty($property)->setAccessible(true);
$reflector->setStaticPropertyValue($property, $value);
$reflector->getProperty($property)->setAccessible(false);
}
Static properties must be defined in the class definition. Therefore, real static properties cannot be created dynamically like regular properties.
For example, if you run this:
<?php
class MyClass
{
public static function createDynamic()
{
$mydynamicvar = 'module';
self::$mydynamicvar = $value;
}
}
MyClass::createDynamic();
var_dump(MyClass::$mydynamicvar);
var_dump(MyClass::$module);
...you'll get this error
Fatal error: Access to undeclared static property: MyClass::$mydynamicvar test.php on line 8
Notice how the error occurs on line 8 when trying to set the property instead of line 14 or 15 (as you might expect if you were simply doing it wrong and dynamically creating static properties was actually possible).
A related problem that IS possible (in PHP 5.4.0 and up) is to include various separate groups of static variable or constant declarations and group them together into one class declaration.
Here is an example:
trait Added1 // This can be located in one Include file
{
static
$x="hello"; // Can declare more variables here
}
trait Added2 // This can be located in another Include file
{
static
$y="world"; // Can declare more variables here
}
class G // Global constant and variable declarations class
{
use Added1, Added2; // Combines all variable declarations
}
echo G::$x." ".G::$y; // Shows "hello world" on the web page
If I have a class that includes a file with a constant like so:
define("FOO", "bar");
Is there a way to make the class include the file with encapsulation so if I use the class somewhere that already has a FOO constant defined it won't break?
Create a static class and use constants would be the best way to encapsulate specific constants:
static class Constants
{
const Name = 'foo';
const Path = 'Bar';
}
And then use like so:
echo Constants::Name; //foo
echo Constants::Path; //bar
in regards to the precheck you can do
function _defined($key,$check_classes = false)
{
if($check_classes)
{
foreach(get_declared_classes() as $class)
{
if(constant($class . '::' . $key) !== null)
{
return true;
}
}
}
if(!defined($key)) //global Scope
{
return true;
}
}
Usage:
class a
{
const bar = 'foo';
}
if(_defined('bar',true)) //This would be true because its within a
{
//Blah
}
If your thinking of a situation like so
class a
{
const b = '?';
}
class b
{
const b = '?';
}
the constants are within the class scope so they would have no affect on one another !
You can check if constant already defined using defined:
<?php
define("FOO", "1");
if (!defined("FOO")) { ## check if constant is not defined yet
define("FOO", "2");
}
echo FOO;
?>
You can use a class contant
class Foo
{
constant FOO = 'bar'
}
However, you will have to include the class before you can use the constant with Foo::FOO. An alternative with regular constants is to use to prefix them with a vendor prefix to make clashes less likely, e.g.
define('JOHN_FOO', 'bar')
or use the newly introduced namespaces (PHP 5.3)
define('JohnIsaacks\FOO', 'bar');
But in all cases, I wonder why you would need that. If you want to load classes, simply add in an autoloader.