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::
Related
I heard static method are used when object has not been instantiated or when you need to call something within a class.
class Show_files{
static private $person = 1;
echo Show_files::$person++;
}
I'd like this to show 2, I know it will work if I put it in an instance or in a method, but why's it not working like it is now?
You are trying to execute code inside a class, but outside of a method. That is illegal syntax. The only things that can go "outside" of the methods are attribute definitions:
class foo {
static $x = 0; // simple variable creation, fixed values. A-OK
public $y = 1+1; // illegal - expressions not permitted
private $z = self::$y++; // double-illegal
echo self::$z // illegal - executing code
}
The $z definition is illegal on two levels - you cannot create $z by reading from the object while it's still being parsed/defined, and you cannot "execute code" (i.e. an "expression") in an attribute definition.
Becouse it's inconsistent with php syntax - you have to place it inside of a method.
Ex.
Show_files{
static private $person = 1;
public static function show()
{
echo self::person++;
}
}
and then Show_files::show()
Change it to
class Show_files{
static private $person = 1;
public static function getPersonCount() {
self::$person++;
echo self::$person;
return;
}
}
and call it
Show_files::getPersonCount();
You have to put this echo inside a method. And then call it elsewhere (for exemple, your view). Watch this : http://php.net/manual/en/language.oop5.basic.php
In PHP sometimes it would be nice if I could define a function or a class with a variable name like
$myfunctionname="test";
function $myfunctionname(){
//...
}
so it would create the function test()
or with classes too like:
$foo = bar;
class $foo {
// lots of complicated stuff
// ...
}
but this doesen't work. like this it would give parse errors!
Is there a solution to this?
(I know, this is not good practise, but just as a workaround, it would be handy)
EDIT: My actual problem:
I have a framework with a migration process where every migration step is in a separate php include file in a folder.
Each file contains only one migration class that contains the name of the include file.
Because the class has to have that certain name, I would like to create the name of the class to a generic name that is created by the filename constant __FILE__
Yes, you can, but I dont want you to.
$classname = "test";
eval("class {$classname}{ public function hello(){ echo \"hello!\"; } }");
$evil_class = new $classname();
$evil_class->hello(); // echo's "hello!"
now, if you don't mind me I'm going for a shower.
You can use a factory pattern:
class poly_Factory {
public function __construct() {
$class = 'poly';
return new $class();
}
}
If that is anything you want to get to.
http://net.tutsplus.com/tutorials/php/understanding-and-applying-polymorphism-in-php/
Scroll down to step 4, last part...
I know you did not ask for that, but what can your question be good for else?
No. This code throws a parse error on line 3 because of the $:
$foo = 'bar';
class $foo {
function hello() {
echo "World";
}
}
$mybar = new bar();
$mybar->hello();
Result:
Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING on line 3
And as Jan Dvorak pointed out in the comments: even if you figure out a way to do this, don't do this.
If you want to create a value object you can just use the stdClass builtin type.
$object = new stdClass;
$object->someValue = "Hello World";
echo $object->someValue;
See it in Action
If you want to assign methods then you have to use the magic __call function, here is how I would do it.
class AnonObject{
private $properties = array();
private $methods = array();
public function __get($property){
return array_key_exists($property, $this->properties)?$this->properties[$property]:null;
}
public function __set($property, $value){
if (!is_string($value) && is_callable($value)){
if ($value instanceof \Closure){
// bind the closure to this object's instance and static context
$this->methods[$property] = $value->bindTo($this,get_class($this));
} else {
// invokable objects
$this->methods[$property] = $value;
}
} else {
$this->properties[$property] = $value;
}
}
public function __call($method, $args){
if (array_key_exists($method, $this->methods)){
call_user_func_array($this->methods[$method], $args);
} else {
throw new RuntimeException("Method ".$method." does not exist on object");
}
}
}
See it In Action
Note, as stated by several other people this is bad practice. If the goal of this exercise is to compose the behavior of an instance of an object at runtime a more maintainable solution would be to use the Strategy Pattern
I have a question regarding "dynamic" class initialising, let me explain what I mean:
$class = 'User';
$user = new $class();
//...is the same as doing
$user = new User();
So... that's not the problem, but I am having some trouble doing the same while calling a static variable from a class, for example:
$class = 'User';
print $class::$name;
Which gives out the following error:
Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM in
Off course I have tested doing print User::$name; and that works. So class works.
Why is this and is there a way around it?
Follow up question:
Also is there any valid reasons to not use this "dynamic" way in creating classes?
This code works good on PHP 5.4.3:
<?php
class A {
public static $var = "Hello";
}
print(A::$var);
$className = "A";
print($className::$var);
?>
This is the answer from the question I linked in the comments:
You can use reflection to do this. Create a ReflectionClass
object given the classname, and then use the getStaticPropertyValue
method to get the static variable value.
class Demo
{
public static $foo = 42;
}
$class = new ReflectionClass('Demo');
$value=$class->getStaticPropertyValue('foo');
var_dump($value);
If you don't have PHP version of 5.3 and above, and you don't want to use reflection (which in my opinion is an overkill - unless you want to access multiple static properties) you can define getter function and call it via call_user_func():
class A {
public static $var = "Hello";
public static function getVar() {
return self::$var;
}
}
$className = "A";
echo call_user_func(array($className, 'getVar'));
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
I trying to learn OOP and I've made this class
class boo{
function boo(&another_class, $some_normal_variable){
$some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $another_class->get($some_normal_variable);
}
}
and I call this somewhere inside the another_class class like
$bla = new boo($bla, $foo);
echo $bla->do_stuff();
But I don't know how to access $bla, $foo inside the do_stuff function
<?php
class Boo
{
private $bar;
public function setBar( $value )
{
$this->bar = $value;
}
public function getValue()
{
return $this->bar;
}
}
$x = new Boo();
$x->setBar( 15 );
print 'Value of bar: ' . $x->getValue() . PHP_EOL;
Please don't pass by reference in PHP 5, there is no need for it and I've read it's actually slower.
I declared the variable in the class, though you don't have to do that.
Ok, first off, use the newer style constructor __construct instead of a method with the class name.
class boo{
public function __construct($another_class, $some_normal_variable){
Second, to answer your specific question, you need to use member variables/properties:
class boo {
protected $another_class = null;
protected $some_normal_variable = null;
public function __construct($another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $some_normal_variable;
}
function do_stuff(){
return $this->another_class->get($this->some_normal_variable);
}
}
Now, note that for member variables, inside of the class we reference them by prefixing them with $this->. That's because the property is bound to this instance of the class. That's what you're looking for...
In PHP, constructors and destructors are written with special names (__construct() and __destruct(), respectively). Access instance variables using $this->. Here's a rewrite of your class to use this:
class boo{
function __construct(&another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $this->another_class->get($this->some_normal_variable);
}
}
You need to capture the values in the class using $this:
$this->foo = $some_normal_variable