I'm trying to iterate through the variables within a PHP class that contains an SplEnum. It doesn't work. Here's the code:
class enum extends SplEnum { const First = 1; }
class fruit
{
public $enum;
public $variable = 2;
public function __construct(enum $enum)
{
$this->enum = $enum;
}
}
$apple = new fruit(new enum(enum::First));
foreach ($apple as $key => $value) {
echo "[$key] => $value\n";
}
This is the output:
[enum] => 1
PHP Fatal error: Uncaught exception 'UnexpectedValueException' with message 'Value not a const in enum enum' in /home/test.php:16
Stack trace:
#0 /home/test.php(16): unknown()
#1 {main}
thrown in /home/test.php on line 16
It seems that what is happening is that the foreach loop is trying to turn each class variable into an enum. How do I correctly iterate through the variables in the class?
The SPL Lib is known to be a buggy one.
You can switch the order of the variable declaration to
public $variable = 2;
public $enum;
And the example will work.
It will also work if you delete the enum property declaration altogether.
class fruit
{
public $variable = 2;
public function __construct(enum $enum)
{
$this->enum = $enum;
}
}
Maybe your best bet is to avoid it, or keep it private/protected.
Related
Look at the following code:
<?php
enum Types:string {
case A = 'a';
case B = 'b';
}
#[Attribute(Attribute::TARGET_CLASS)]
class MyAttribute {
public function __construct(public readonly array $mapping)
{
}
}
#[MyAttribute(mapping: [Types::A->value => ''])]
class Entity {
}
It has error Constant expression contains invalid operations. I would like to use Enum value in my attribute for defining configuration. Seem like it is bug in php. Should it be reported or something?
The problem is that when we call Types::A->value it actually creates instance of an enum, which is not a constant value.
To solve this problem define a constant and reference it.
<?php
abstract class Type {
public const A = 'a';
public const B = 'b';
}
enum TypesEnum:string {
case A = Type::A;
case B = Type::B;
}
#[Attribute(Attribute::TARGET_CLASS)]
class MyAttribute {
public function __construct(public readonly array $mapping)
{
}
}
#[MyAttribute(mapping: [Type::A => ''])]
class Entity {
}
Watch out for this issue in php
I have a simple class in PHP with a constant. In the constructor I'd like to use this constant in a for loop, however both the IDE and PHP say:
Notice: Use of undefined constant DECK_SUITS - assumed 'DECK_SUITS' in /../Deck.php on line 18
Here's the code of my class:
class Deck
{
private $cards = [];
const DECK_SUITS = [Suit::Club, Suit::Diamond, Suit::Heart, Suit::Spade];
const DECK_RANKS = [Rank::Ace, Rank::Two, Rank::Three, Rank::Four, Rank::Five, Rank::Six, Rank::Seven, Rank::Eight, Rank::Nine,
Rank::Ten, Rank::Jack, Rank::Queen, Rank::King];
public function __construct() {
foreach(DECK_SUITS as $suit) {
foreach(DECK_RANKS as $rank) {
$card = new Card($suit, $rank);
$this->cards[] = $card;
}
}
}
So this error is shown for both DECK_SUITS as well as DECK_RANKS in my foreach loop.
I can't find what's wrong with my code.
That's because they're class constants not global constants (created using the define() function), and need to be referenced differently, identifying the class that they're defined in:
foreach(Deck::DECK_SUITS as $suit) {
foreach(Deck::DECK_RANKS as $rank) {
or self::DECK_SUITS and self::DECK_RANKS from within the class where they're defined
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
From the string name of a class, can I get a static variable?
Somewhere in a parent class, I need to find the value of a static variable of one of the possible child classes, determined by the current instance.
I wrote:
$class = get_class($this);
$value = isset($class::$foo['bar']) ? $class::$foo['bar'] : 5;
In this example, the subclass whose name is in $class has a public static $foo.
I know using $class::$foo['bar'] is not a very beautiful piece of code, but it gets the job done on PHP 5.3.4.
In PHP 5.2.6 though, I am getting a syntax error:
Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM, expecting ',' or ')'
Is there an alternative way that would work on PHP 5.2.4+ that would get the same thing done?
EDIT: Reflection is better.
You can try the get_class_vars method. No access to PHP 5.2.6, but this works in 5.2.11...
class Test {
public static $foo;
function __construct() {
echo("...Constructing...<br/>");
Test::$foo = array();
Test::$foo['bar'] = 42;
}
function __toString() {
return "Test";
}
}
$className = 'Test';
$class = new $className();
$vars = get_class_vars($className);
echo($vars['foo']['bar'] . "<br/>");
Output:
...Constructing...
42
The reason that this does not work in PHP 5.2, is because before PHP 5.3 you are not allowed to use variables in the classname. So, if possible use eval for this.
eval('$result = ' . $c . '::$foo[\'bar\'];');
echo $result;
Otherwise, you're forced to use a function in the child class to receive the value. For example:
class MyParent {
public function __construct() {
$var = $this->_getVariable();
echo $var['bar'];
}
}
class MyChild extends MyParent {
static $var = array('bar' => 'foo');
protected function _getVariable() {
return self::$var;
}
}
new MyChild();
class Bar1 {
static $var = array('index' => 'value');
}
class Bar2 extends Bar1 {
}
class Foo extends Bar2 {
static $var = array('index' => 'value in Foo');
public function __construct() {
echo parent::$var['index'];
}
}
$foo = new Foo();
will output 'value', but not 'value in Foo'
Hope, that's what you are looking for.
You can get class static/call static method in the class you are working in using self key word or for parent class using parent. You can get that error on php 5.2.6 because of changes in get_class function in PHP 5.3.0
I am trying to access static member of a class.
my class is:
class A
{
public static $strName = 'A is my name'
public function xyz()
{
..
}
..
}
//Since I have bunch of classes stored in an array
$x = array('A');
echo $x::$strName;
I am getting error while printing. How can I print 'A is my name'
If A is a class, you can access it directly via A::$strName.
class A {
public static $strName = 'A is my name';
}
echo A::$strName; // outputs "A is my name"
Update:
Depending on what you have inside your array, whether its what I like to define as class objects or class literals could be a factor. I distinguish these two terms by,
$objClasses = array(new A(), new B()); // class objects
$myClasses = array('A','B'); // class literals
If you go the class literals approach, then using a foreach loop with PHP5.2.8 I am given a syntax error when using the scope resolution operator.
foreach ($myClasses as $class) {
echo $class::$strName;
//syntax error, unexpected '::', expecting ',' or ';'
}
So then I thought about using the class objects approach, but the only way I could actually output the static variable was with an instance of an object and using the self keyword like so,
class A {
public static $strName = 'A is my name';
function getStatic() {
return self::$strName;
}
}
class B {
public static $strName = 'B is my name';
function getStatic() {
return self::$strName;
}
}
And then invoke that method when iterating,
foreach($objClasses as $obj) {
echo $obj->getStatic();
}
Which at that point why declare the variable static at all? It defeats the whole idea of accessing a variable without the need to instantiate an object.
In short, once we have more information as to what you would like to do, we can then go on and provide better answers.
If you want a working version for PHP5.2, you can use reflection to access the static property of a class.
class A {
static $strName= '123';
}
$lstClass = array('A');
foreach ($lstClass as $value) {
$c = new ReflectionClass($value);
echo $c->getStaticPropertyValue('strName');
}
Demo : http://ideone.com/HFJCW
You have a syntax error with missing semicolon and because it is an array you need to access the index of 0, or else it would be trying to call class 'Array'.
class A
{
public static $strName = 'A is my name';
public function xyz()
{
// left blank and removed syntax error
}
}
$x = array('A');
echo $x[0]::$strName;
Should fix it.
UPDATE
If you want to iterate over an array to call a class variable:
$x = array('A', 'B');
foreach ($x as $class) {
echo $class::$strName;
}
Not sure why you would want that, but there you go. And this has been tested, no errors were thrown, valid response of A is my name was received.
EDIT
Apparently this only works under PHP 5.3
I do find next one simple solution but don't know whether its good one or not.
My soln is:
eval('return '.$x[0].'::$strName;');
From inside a class and want to access a static data member of its own you can also use
static::
instead of
self::
Assuming you have a constant defined in a class:
class Foo {
const ERR_SOME_CONST = 6001;
function bar() {
$x = 6001;
// need to get 'ERR_SOME_CONST'
}
}
Is it possible with PHP?
You can get them with the reflection API
I'm assuming you would like to get the name of the constant based on the value of your variable (value of variable == value of constant). Get all the constants defined in the class, loop over them and compare the values of those constants with the value of your variable.
Note that with this approach you might get some other constant that the one you want, if there are two constants with the same value.
example:
class Foo {
const ERR_SOME_CONST = 6001;
const ERR_SOME_OTHER_CONST = 5001;
function bar() {
$x = 6001;
$fooClass = new ReflectionClass ( 'Foo' );
$constants = $fooClass->getConstants();
$constName = null;
foreach ( $constants as $name => $value )
{
if ( $value == $x )
{
$constName = $name;
break;
}
}
echo $constName;
}
}
ps: do you mind telling why you need this, as it seems very unusual ...
Here's what I did to achieve it. Inspired by Jan Hancic.
class ErrorCode
{
const COMMENT_NEWCOMMENT_DISABLED = -4;
const COMMENT_TIMEBETWEENPOST_ERROR = -3;
/**
* Get error message of a value. It's actually the constant's name
* #param integer $value
*
* #return string
*/
public static function getErrorMessage($value)
{
$class = new ReflectionClass(__CLASS__);
$constants = array_flip($class->getConstants());
return $constants[$value];
}
}
With Reflection:
$class = new ReflectionClass("Foo");
$constants = $class->getConstants();
$constants is an array which holds all the names and values of the constants defined in class Foo.
All the other answers cover the essential points. But, if crazy one liners is your thing, then:
function getConstantName($class, $value)
{
return array_flip((new \ReflectionClass($class))->getConstants())[$value];
}
If you need to handle the case where the value might not actually be one of the constants, then you can give up an extra line:
function getConstantName($class, $value)
{
$map = array_flip((new \ReflectionClass($class))->getConstants());
return (array_key_exists($value, $map) ? $map[$value] : null);
}
I know this is an old question and all, but I still feel that I have some useful input. I implemented this using an abstract class that all my enums extend. The abstract class contains a generic toString() method;
abstract class BaseEnum{
private final function __construct(){ }
public static function toString($val){
$tmp = new ReflectionClass(get_called_class());
$a = $tmp->getConstants();
$b = array_flip($a);
return ucfirst(strtolower($b[$val]));
}
}
//actual enum
final class UserType extends BaseEnum {
const ADMIN = 10;
const USER = 5;
const VIEWER = 0;
}
This way you can get a human readable string to use in output, on every enum that extends the base enum. Furthermore, your implementation of the enum, being final, cannot be extended and because the constructor in the BaseEnum is private it can never be instantiated.
So for instance, if you show a list of all usernames with their types you can do something like
foreach($users as $user){
echo "<li>{$user->name}, ".UserType::toString($user->usertype)."</li>";
}
All constant can be assigned to an array using this function.
$const = get_defined_constants();
then using following function you can print the array structure
echo "<pre>";
print_r($const);
and you can see more explanation here www.sugunan.com
Warning: This way you should NOT program... ( if youre not sure what youre doing :) )
I wrote 1 row which echos constants and their numeric values by your choice of CATEGORY_
so here is the list of CATEGORY_ ERR_
foreach(get_defined_constants() as $key => $value) if(strlen($key)>5) if(substr($key, 0,5)=="ERR_") echo"<br>Found an php ERR_ constant! : ".$key."=>".$value;
And if you want just the one youre looking for by number => I created 1row function:
//input parameters: CATEGORYNAME_ , #constantNumber
function getConstantName($category,$constantNumber){foreach(get_defined_constants() as $key => $value) if(strlen($key)>strlen($category)) if(substr($key, 0,strlen($category))==$category) if($value==$constantNumber) return $key; return "No constant found.";}
So for example some info constant with number 64:
echo "NameOfConstant: ".getConstantName("INFO_",64);
will output something like: NameOfConstant: INFO_LICENSE
OK, OK, I know everything is already covered :)
But Jan Hančič asked for use case, so I'll share mine.
Aside: everyone seems to use array_flip(). Why not array_search()?
I needed it in a class that extends \Exception and is base class of small set of my concrete exceptions. Each of those concrete exception classes covers a broad exception domain and has defined several precise exception causes. Reason? I don't want to have a horde of exceptions to maintain and remember of. Also, there is exception handler set that dumps exception's guts into log file - and it's here I need to get the constant name as trying to decipher exception cause from status in quite painful.
Examples from my CLI scripts:
class AbstractException extends Exception {
public function getName() {
return array_search($this->getCode(), (new ReflectionClass($this))->getConstants());
}
}
class SyntaxException extends AbstractException {
const BAD_SYNTAX = 90;
const REQUIRED_PARAM = 91;
const REQUIRED_VALUE = 92;
const VALUE_TYPE = 93;
const VALUE_OUT_OF_BOUNDS = 94;
public function __construct ($message = "", $code = self::BAD_SYNTAX, Exception $previous = NULL) {
$script = basename($GLOBALS['argv'][0]);
echo "Invalid syntax: $message \nSee: `$script --help` for more information\n";
parent::__construct($message, $code, $previous);
}
}
// in autoload include
set_exception_handler(function(Exception $e) {
error_log(basename($GLOBALS['argv'][0]) . ';'. date('Y-m-d H:i:s') .';'. $e->getName() .';'. $e->getMessage() .';'. $e->getFile() .';'. $e->getLine() ."\n", 3, 'error.log');
exit ($e->getCode());
});
class OrderStatus
{
public const PENDING = 1;
public const PROCESSED = 2;
public static function getStatusCode($value)
{
$class = new ReflectionClass(__CLASS__);
$constants = array_flip($class->getConstants());
return $constants[$value] ?? null;
}
// OrderStatus::getStatusCode(1); // 'PENDING'
}
if you need to get the constant value on a method of the same class, you just need to use the self operator. You could use reflection if you want to use the constants on another class
class Foo {
const ERR_SOME_CONST = 6001;
function bar() {
self::ERR_SOME_CONST;
}
}