Can a php class' static member be pointed? - php

class ab{
public static $abc = 34;
public static function asd(){
$a = "abc";
echo self::$a; //output 34;
}
}
ab::asd();
i want to find a way to point to a class static member .like the example above,how can i make this work?

If you access a static variable, the syntax is the following:
MyClass::$variable
So what you're doing lacks the indirection:
echo self::$$a; //output 34;
This works with regular variables the same way:
$variable
and with indirection:
$name = "variable";
$$name
An advice for your next question: Try to be more precise in your question. Pay attention to the following:
What you have
What it should do
What actually does
Where the error occurs if you know
This helps to give relevant answers more quickly instead of engaging in a meta-discussion to clarify your question.

Related

Using $GLOBALS[] variable in PHP class function

I'm trying to assign $GLOBALS['a'] variable in function from class, but haven't succeeded.
Here is my code:
<?php
$GLOBALS['a'] = "alter";
class db_data
{
public $a;
function __construct()
{
$this->a = $GLOBALS['a'];
}
}
$db = new db_data;
echo $db->$a;
?>
And produced this error:
Notice: Undefined property: db_data::$alter.....
I tried to search on SO for this, but all questions were different and it did not resolve my problem.
Answers are in the question comments, but here's why it's happening
You're accidentally using the variable variables feature of PHP. When you call $thing->$a, you're actually getting the value of $a (which defined by the $GLOBALS['a'] = "alter"; line), and then getting the property of $thing with that value.
As stated in your comments, you should simply echo $db->a, as that's how PHP properties are accessed
Also, Watch out!, if the value of $a is changed elsewhere in the global scope, your db_data class will reflect that change, which you probably don't want.

More About PHP OOP - Classes within Classes

I have been told that a class cannot be defined within a class in PHP. However, in my own example this seems to work which has me confused:
class_test.php:
require('class_1.php');
new class_1
//Need $missing_variable here.
class_1.php
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback";
$missing_variable = "Where Did I Go?";
}
require('class_2.php');
new class_2('callback_function');
}
public function __construct(){
$this->function_1();
}
}
class_2.php
class class_2{
public function __construct($callback){
echo "Hello World - ";
call_user_func($callback);
}
}
Loading class_test.php prints out
Hello World - A Callback
Question: How do I define $missing_variable such that I can get it where I need it?
In case anyone in the future has a similar problem, however unlikely that may be, I want to link to the codepad from below that shows the $missing_variable echo'd from outside the classes:
http://codepad.org/tRk0XWG7
Thanks again everyone.
Note: This is a follow up.
You can declare a class within a function. That's known as conditional declaration, i.e. only if the function is called will the class be declared. It doesn't make much of a difference then whether you include a file with the class declaration or if you type out the code inside the function.
This does not mean however that the classes share any sort of scope or data. Only the declaration is conditionally nested, it still has the same functionality and scope as explained before.
Your confusion about the callback can be explained by the same thing. When class_1::function_1 is executed the first time, the function callback_function is being defined. This is a regular global function that can be called from anywhere. It's not bound to the class in any way. You will also notice that you cannot execute class_1::function_1 a second time, PHP will complain that callback_function already exists when you're trying to declare it again.
As for the comment in the source code //How do I declare this variable so that it is available where I need it?: You don't. That variable is a local variable inside a function. It's only in scope inside the function. You can return its value from the function like any other return value if you want to. (You could make it global, but for the love of god don't!) If you need that value somewhere else, don't declare it as a variable inside a function, because only the function can access it then.
You would return $missing_variable in a few places. See below. (This isn't the only way to do it, mind you)
http://codepad.org/tf08Vgdx
<?
class class_2{
public function __construct($callback){
echo "Hello World - ";
$missing = $callback();
$this->missing = $missing;
}
}
class class_1{
public function function_1(){
function callback_function(){
echo "A Callback. ";
$missing_variable = "Where Did I Go?";
return $missing_variable;
}
$class2 = new class_2('callback_function');
return $class2->missing;
}
public function __construct(){
$this->missing = $this->function_1();
}
}
$class = new class_1();
echo $class->missing;

Find the name of a calling var

Anyone has an idea if this is at all possible with PHP?
function foo($var) {
// the code here should output the value of the variable
// and the name the variable has when calling this function
}
$hello = "World";
foo($hello);
Would give me this output
varName = $hello
varValue = World
EDIT
Since most people here 'accuse' me of bad practices and global variables stuff i'm going to elaborate a little further on why we are looking for this behaviour.
the reason we are looking at this kind of behaviour is that we want to make assigning variables to our Views easier.
Most of the time we are doing this to assign variables to our view
$this->view->assign('products', $products);
$this->view->assign('members', $members);
While it would be easier and more readable to just be able to do the following and let the view be responsible to determining the variable name the assigned data gets in our views.
$this->view->assign($products);
$this->view->assign($members);
Short answer: impossible.
Long answer: you could dig through apd, bytekit, runkit, the Reflection API and debug_backtrace to see if any obscure combination would allow you to achieve this behavior.
However, the easiest way is to simply pass the variable name along with the actual variable, like you already do. It's short, it's easy to grasp, it's flexible when you need the variable to have a different name and it is way faster than any possible code that might be able to achieve the other desired behavior.
Keep it simple
removed irrelevant parts after OP edited the question
Regardless of my doubt that this is even possible, I think that forcing a programmer on how to name his variables is generally a bad idea. You will have to answer questions like
Why can't I name my variable $arrProducts instead of $products ?
You would also get into serious trouble if you want to put the return value of a function into the view. Imagine the following code in which (for whatever reason) the category needs to be lowercase:
$this->view->assign(strtolower($category));
This would not work with what you're planning.
My answer therefore: Stick to the 'verbose' way you're working, it is a lot easier to read and maintain.
If you can't live with that, you could still add a magic function to the view:
public function __set($name, $value) {
$this->assign($name, $value);
}
Then you can write
$this->view->product = $product;
I don't think there is any language where this is possible. That's simply not how variables work. There is a difference between a variable and the value it holds. Inside the function foo, you have the value, but the variable that held the value is not available. Instead, you have a new variable $var to hold that value.
Look at it like this: a variable is like a bucket with a name on it. The content (value) of the variable is what's inside the bucket. When you call a function, it comes with its own buckets (parameter names), and you pour the content of your bucket into those (well, the metaphor breaks down here because the value is copied and still available outside). Inside the function, there is no way to know about the bucket that used to hold the content.
What you're asking isn't possible. Even if it was, it would likely be considered bad practice as its the sort of thing that could easily get exploited.
If you're determined to achieve something like this, the closest you can get would be to pass the variable name as a string and reference it in the function from the $GLOBALS array.
eg
function this_aint_a_good_idea_really($var) {
print "Variable name: {$var}\n";
print "Variable contents: {$GLOBALS[$var]}\n";
}
$hello="World";
this_aint_a_good_idea_really('hello');
But as I say, that isn't really a good idea, nor is it very useful. (Frankly, almost any time you resort to using global variables, you're probably doing something wrong)
Its not impossible, you can find where a function was invoked from debug_backtrace() then tokenize a copy of the running script to extract the parameter expressions (what if the calling line is foo("hello $user, " . $indirect($user,5))?),
however whatever reason you have for trying to achieve this - its the wrong reason.
C.
Okay, time for some ugly hacks, but this is what I've got so far, I'll try to work on it a little later
<?php
class foo
{
//Public so we can test it later
public $bar;
function foo()
{
//Init the array
$this->bar = array();
}
function assign($__baz)
{
//Try to figure out the context
$context = debug_backtrace();
//assign the local array with the name and the value
//Alternately you can initialize the variable localy
//using $$__baz = $context[1]['object']->$__baz;
$this->bar[$__baz] = $context[1]['object']->$__baz;
}
}
//We need to have a calling context of a class in order for this to work
class a
{
function a()
{
}
function foobar()
{
$s = "testing";
$w = new foo();
//Reassign local variables to the class
foreach(get_defined_vars() as $name => $val)
{
$this->$name = $val;
}
//Assign the variable
$w->assign('s');
//test it
echo $w->bar['s'];
}
}
//Testrun
$a = new a();
$a->foobar();
impossible - the max. ammount of information you can get is what you see when dumping
debug_backtrace();
Maybe what you want to do is the other way around, a hackish solution like this works fine:
<?php
function assign($val)
{
global $$val;
echo $$val;
}
$hello = "Some value";
assign('hello');
Ouputs: Some value
What you wish to do, PHP does not intend for. There is no conventional way to accomplish this. In fact, only quite extravagant solutions are available. One that remains as close to PHP as I can think of is creating a new class.
You could call it NamedVariable, or something, and as its constructor it takes the variable name and the value. You'd initiate it as $products = new NamedVariable('products', $productData); then use it as $this->view->assign($products);. Of course, your declaration line is now quite long, you're involving yet another - and quite obscure - class into your code base, and now the assign method has to know about NamedVariable to extract both the variable name and value.
As most other members have answered, you are better off suffering through this slight lack of syntactic sugar. Mind you, another approach would be to create a script that recognizes instances of assign()'s and rewrites the source code. This would now involve some extra step before you ran your code, though, and for PHP that's silly. You might even configure your IDE to automatically populate the assign()'s. Whatever you choose, PHP natively intends no solution.
This solution uses the GLOBALS variable. To solve scope issues, the variable is passed by reference, and the value modified to be unique.
function get_var_name(&$var, $scope=FALSE) {
if($scope) $vals = $scope;
else $vals = $GLOBALS;
$old = $var;
$var = $new = 'unique'.rand().'value';
$vname = FALSE;
foreach ($vals as $key => $val) {
if($val === $new) $vname = $key;
}
$var = $old;
return $vname;
}
$testvar = "name";
echo get_var_name($testvar); // "testvar"
function testfunction() {
$var_in_function = "variable value";
return get_var_name($var_in_function, get_defined_vars());
}
echo testfunction(); // "var_in_function"
class testclass {
public $testproperty;
public function __constructor() {
$this->testproperty = "property value";
}
}
$testobj = new testclass();
echo get_var_name($testobj->testproperty, $testobj); // "testproperty"

PHP Using a variable when calling a static method

I have three classes that all have a static function called 'create'.
I would like to call the appropriate function dynamically based on the output from a form, but am having a little trouble with the syntax. Is there anyway to perform this?
$class = $_POST['class'];
$class::create();
Any advice would be greatly appreciated.
Thanks.
If you are working with PHP 5.2, you can use call_user_func (or call_user_func_array) :
$className = 'A';
call_user_func(array($className, 'method'));
class A {
public static function method() {
echo 'Hello, A';
}
}
Will get you :
Hello, A
The kind of syntax you were using in your question is only possible with PHP >= 5.3 ; see the manual page of Static Keyword, about that :
As of PHP 5.3.0, it's possible to
reference the class using a variable.
The variable's value can not be a
keyword (e.g. self, parent and
static).
What you have works as of PHP 5.3.
ps. You should consider cleaning the $_POST['class'] since you cannot be sure what will be in it.
use call_user_func
heres an example from php.net
class myclass {
static function say_hello()
{
echo "Hello!\n";
}
}
$classname = "myclass";
call_user_func(array($classname, 'say_hello'));
call_user_func($classname .'::say_hello'); // As of 5.2.3
$myobject = new myclass();
call_user_func(array($myobject, 'say_hello'));
I believe this can only be done since PHP 5.3.0. Check this page and search for $classname::$my_static to see the example.
I may be misunderstanding what you want, but how about this?
switch ($_POST['ClassType']) {
case "Class1":
$class1::create();
break;
case "Class2":
$class2::create();
break;
// etc.
}
If that doesn't work, you should look into EVAL (dangerous, be careful.)

Getting static property from a class with dynamic class name in PHP

I have this:
one string variable which holds the class name ($classname)
one string variable with holds the property name ($propertyname)
I want to get that property from that class, the problem is, the property is static and I don't know how to do that.
If the property weren't static, it would have been:
$classname->$propertyname;
if the property were a method, I could have used call_user_function
call_user_func(array($classname, $propertyname));
But in my case, am I just lost. I am however hoping that it is possible. With the thousands of functions that PHP has, he'd better have something for this as well. Maybe I'm missing something?
Thanks!
Edit:
for those with eval() solutions: thanks, but it is out of the question
for those with get _class _vars() solutions: thanks, but it seems it returns "the default properties of the given class" (php.net), and yes, I would like that value to be changable (even though it does help me in some of the cases)
If you are using PHP 5.3.0 or greater, you can use the following:
$classname::$$propertyname;
Unfortunately, if you are using a version lower than 5.3.0, you are stuck using eval() (get_class_vars() will not work if the value is dynamic).
$value = eval($classname.'::$'.$propertyname.';');
EDIT: I've just said get_class_vars() wouldn't work if the value is dynamic, but apparently, variable static members are part of "the default properties of a class". You could use the following wrapper:
function get_user_prop($className, $property) {
if(!class_exists($className)) return null;
if(!property_exists($className, $property)) return null;
$vars = get_class_vars($className);
return $vars[$property];
}
class Foo { static $bar = 'Fizz'; }
echo get_user_prop('Foo', 'bar'); // echoes Fizz
Foo::$bar = 'Buzz';
echo get_user_prop('Foo', 'bar'); // echoes Buzz
Unfortunately, if you want to set the value of the variable, you will still need to use eval(), but with some validation in place, it's not so evil.
function set_user_prop($className, $property,$value) {
if(!class_exists($className)) return false;
if(!property_exists($className, $property)) return false;
/* Since I cannot trust the value of $value
* I am putting it in single quotes (I don't
* want its value to be evaled. Now it will
* just be parsed as a variable reference).
*/
eval($className.'::$'.$property.'=$value;');
return true;
}
class Foo { static $bar = 'Fizz'; }
echo get_user_prop('Foo', 'bar'); // echoes Fizz
set_user_prop('Foo', 'bar', 'Buzz');
echo get_user_prop('Foo', 'bar'); // echoes Buzz
set_user_prop() with this validation should be secure. If people start putting random things as $className and $property, it will exit out of the function as it won't be an existing class or property. As of $value, it is never actually parsed as code so whatever they put in there won't affect the script.
I think this is the simplest:
$foo = new ReflectionProperty('myClassName', 'myPropertyName');
print $foo->getValue();
To return a variable value that is set by a Static Variable you need to call:
$static_value = constant($classname.'::'.$propertyname);
Check out the documentation :: PHP Constant Documentation
You should be able to do something like:
eval("echo $classname::$propertyname;");
I just did a quick test and got this to work for me. Not sure if there's a better way or not, but I wasn't able to find one.
'eval' looks so close to 'evil', and I hate using it and/or seeing it in code. With a few ideas from other answers, here's a way to avoid it even if your php isn't 5.3 or higher.
Changed to reflect testing based on a comment.
class A {
static $foo = 'bar';
}
A::$foo = 'baz';
$a = new A;
$class = get_class($a);
$vars = get_class_vars($class);
echo $vars['foo'];
Outputs 'baz'.
One thing I noticed is that you can't set variables which are protected in static classes as the eval() command runs in a scope outside the class. The only thing to get around this would be to implement a static method inside the/every class which runs the eval(). This method could be protected as the call_user_func() [to call the setter method] also runs from inside the class.
Potentially relevant: discussion on late static binding in PHP - When would you need to use late static binding?.
get_class_vars is not same as get_object_vars.
I think get_clas_vars should return the original property values.
Even if for you said eval is out of the question, prior PHP 5.3 the easiest solution is still by using eval:
eval("\$propertyval = $classname::\$propertyname;");
echo $propertyval;
Getting and setting both static and non static properties without using Reflection
Using Reflection works but it is costly
Here is what I use for this purpose,
It works for PHP 5 >= 5.1.0 because I'm using property_exist
function getObjectProperty($object, $property)
{
if (property_exists(get_class($object), $property)) {
return array_key_exists($property, get_object_vars($object))
? $object->{$property}
: $object::$$property;
}
}
function setObjectProperty($object, $property, $value)
{
if (property_exists(get_class($object), $property)) {
array_key_exists($property, get_object_vars($object))
? $object->{$property} = $value
: $object::$$property = $value;
}
}
You can use ReflectionClass:
class foo
{
private static $bar = "something";
}
$class = "foo";
$reflector = new ReflectionClass($class);
$static_vars = $reflector->getStaticProperties();
var_dump($static_vars["bar"]);

Categories