I have a very simple class:
class MyClass
{
public function someFunction()
{
echo array_key_exists( 'dynamicVariable', $GLOBALS ) ? 'true' : 'false';
}
}
I want to define a variable 'on the fly' inside 'someFunction', but I can't seem to figure out how to do this inside function scope.
$classInstance = new MyClass();
$varName = 'dynamicVariable';
$classInstance->$varName;
What I want to do:
$classInstance = new MyClass();
$varName = 'dynamicVariable';
$classInstance->functionScopeReference->$varName;
$classInstance->myFunction(); <-- this will print TRUE
How can do the same thing, but define it in someFunction scope, instead of MyClass scope? Thanks
Posting as a community wiki in order to satisfy the OP, since dbf hasn't posted the comment to close the question.
"Short answer, you can't from outside of the methods scope, unless the variable is a property used inside any method. – dbf"
...
"#dbf thank you! you can post this comment as an answer and I will mark it – 0x29a"
By using the $this keyword... I would suggest a good 101 course on object oriented programming which should explain scope better then I could...
class MyClass
{
public function someFunction($foo)
{
$this->dynamicVariable = $foo;
}
}
$classInstance = new MyClass();
$classInstance->someFunction('dynamicVariable');
echo $classInstance->dynamicVariable;
EDIT: to better answer OP's question (sorry for not reading that correctly!): although it does not change scope, a workaround would be to use getters and setters and make your properties private:
class MyClass
{
private $property_one; // can't access this without using the getPropertyOne function
private $property_two;
public function setPropertyOne($bool)
{
$this->property_one = $bool;
}
public function getPropertyOne()
{
return $this->property_one;
}
public function setPropertyTwo($bool)
{
$this->property_two = $bool;
}
public function getPropertyTwo()
{
return $this->property_two;
}
}
$classInstance = new MyClass();
// trying to access the properties without using the functions results in an error
echo $classInstance->property_one;
$classInstance->setPropertyOne(true);
echo $classInstance->getPropertyOne();
$classInstance->setPropertyTwo(false);
echo $classInstance->getPropertyTwo();
Related
I try to create some sort of setup class, like global values for the page.
The PHP-code
class globals
{
public $page;
public function __construct()
{
}
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
}
class get
{
public function page()
{
$globals = new globals();
return $globals->page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page(); // Short function to be in a template
Question
My class forget the value I set. Why is that?
Do I have to use global variables?
Is this the correct approach for the problem?
The variable is set on an object, not on a class.
For each class, you can instantiate multiple objects. Each of those have their own variable scope.
Edit:
I forgot to include the easiest, and least verbose solution to your problem. AFAIK, you're looking for a way to check what page you're on. Constants will do just that:
defined('MY_CURRENT_PAGE') || define('MY_CURRENT_PAGE','My Value');
//use anywhere like so:
echo 'Currently on page: '.MY_CURRENT_PAGE;
My class forget the value I set. Why is that?
Quite simple: your page member function isn't static, yet you call it as though it is: get::page(). Even if you were to fix this, you're creating a new instance in the page method, but you're not preserving a reference too it anywhere, so each page call will create a new globals instance, that has nothing set.
Do I have to use global variables?
No, unless you're Really desperate, never use globals
Is this the correct approach for the problem?
No, if it doesn't work, it's not correct (IMHO).
Well, what is, you might ask. There are several ways to go about this:
class globals
{
public static $page = null;//make this static, meaning all instances will share this var
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get
{
private $_globalsInstance = null;
public function __construct(globals $instance = null)
{
$this->_globalsInstance = $instance;
}
private function _getGlobals()
{
if (!$this->_globalsInstance instanceof globals)
{
$this->_globalsInstance = new globals();
}
return $this->_globalsInstance;
}
public function page()
{
return $this->_getGlobals()::$page;
}
}
Personally, however, I wouldn't work like this, I'd just pass my instances to wherever I need them (as arguments to functions/methods or just instantiate them in a scope that will be accessible:
class globals
{
public $page = null;//make this static, meaning all instances will share this var
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
}
$page = new globals();
$page->set_page('foobar');
someFunction($page);
$someObject->renderPage($page);
require_once('specificScript.php');
//inside required script:
echo $page->page;
Do I have to use global variables?
Not, if your can use PHP 5.3
Is this the correct approach for the problem?
Better to use a generic class for this, or use static properties of objects
<?php
class globals
{
public static $page;
public function __construct()
{
}
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get
{
public static function page()
{
return globals::$page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page(); // Short function to be in a template
P.S.
But this is not a nice approach
$globals there
class get
{
public function page()
{
$globals = new globals();
return $globals->page;
}
}
and there
$globals = new globals();
$globals->set_page('My value');
are different inctances of globals class.
One of the solutions is to make $page var static
public static $page;
I hope this helps
UPD:
Also you might apply Singleton to globals class and request for its insnance instead of creating new one directly:
globals::getInstance()->setPage('Page');
and
return globals::getInstance()->getPage();
In this case $page doesn't have to be static.
I'm not sure the other answers are very clear. You have created 2 classes. As such they have different scopes. As writen you can't access the original variable $page from the get class because it's outside the scope. Your page function in fact creates a new version of the object $globals without $page set. Normally you would place both your set and get functions in the initial object/class. Though it would be possible to use two class by calling the first class from the second and setting the page. Why you would want to do that I'm not sure.
if I were writing the class it would look like this.
class globals
{
public $page;
public function __construct()
{
}
public function set_page($value)
{
$this->page = $value; // Maybe from a database
}
public function get_page()
{
return $this->page;
}
}
Actually I would probably set page to private not public. As public I guess you don't need a get function.
for using methods of the class without object you must use static definition. but anyway you put value for one class object and try to get it from another...
Perhaps this will help you continue on your coarse:
class globals
{
public static $page;
public function set_page($value)
{
self::$page = $value; // Maybe from a database
}
}
class get extends globals
{
public function page()
{
$globals = new globals();
return parent::$page;
}
}
$globals = new globals();
$globals->set_page('My value');
echo get::page();
?>
I'm trying to determine whether or not a given object has been created. I see there are methods for class_exists and method_exists but what I'm trying to figure out is if new Foo() has been called (and hopefully figure out what variable it was assigned to, but that is not as important).
If I understand you correctly you are trying to initialize object only once. If this is the case why not to use singleton pattern? This will free you from checking of existence of object:
class MyClass {
private static $instance;
private function __construct() {}
public static function getInstance() {
if (empty(self::$instance)) {
self::$instance = new __CLASS__();
}
return self::$instance;
}
}
You can use this code like this:
$obj = MyClass::getInstance();
With similar approach you can define additional helper static methods which will check whether object was instantiated or not. You just need to keep instance statically inside your class.
Edit: After seeing the reason you are needing this in the comments above, this is definitely not the way to go about it.
Here ya go. It could be optimized a little, but should work fine.
Also, passing get_defined_vars() to the function every time is necessary because that function only retrieves the vars within the scope it's called. Calling it inside the function would only give the vars within the scope of that function.
<?php
function isClassDeclared($class_name, $vars, $return_var_name = FALSE) {
foreach ($vars AS $name => $val) {
if (is_object($val) && $val instanceof $class_name)
return $return_var_name ? $name : TRUE;
}
return FALSE;
}
class Foo {}
$foo = new Foo;
echo '<pre>';
var_dump(isClassDeclared('foo', get_defined_vars(), TRUE));
var_dump(isClassDeclared('bar', get_defined_vars(), TRUE));
echo '</pre>';
If I have an instance in PHP, what's the easiest way to get to a static property ('class variable') of that instance ?
This
$classvars=get_class_vars(get_class($thing));
$property=$classvars['property'];
Sound really overdone. I would expect
$thing::property
or
$thing->property
EDIT: this is an old question. There are more obvious ways to do this in newer
PHP, search below.
You need to lookup the class name first:
$class = get_class($thing);
$class::$property
$property must be defined as static and public of course.
From inside a class instance you can simply use self::...
class Person {
public static $name = 'Joe';
public function iam() {
echo 'My name is ' . self::$name;
}
}
$me = new Person();
$me->iam(); // displays "My name is Joe"
If you'd rather not
$class = get_class($instance);
$var = $class::$staticvar;
because you find its two lines too long, you have other options available:
1. Write a getter
<?php
class C {
static $staticvar = "STATIC";
function getTheStaticVar() {
return self::$staticvar;
}
}
$instance = new C();
echo $instance->getTheStaticVar();
Simple and elegant, but you'd have to write a getter for every static variable you're accessing.
2. Write a universal static-getter
<?php
class C {
static $staticvar = "STATIC";
function getStatic($staticname) {
return self::$$staticname;
}
}
$instance = new C();
echo $instance->getStatic('staticvar');
This will let you access any static, though it's still a bit long-winded.
3. Write a magic method
class C {
static $staticvar = "STATIC";
function __get($staticname) {
return self::$$staticname;
}
}
$instance = new C();
echo $instance->staticvar;
This one allows you instanced access to any static variable as if it were a local variable of the object, but it may be considered an unholy abomination.
classname::property;
I think that's it.
You access them using the double colon (or the T_PAAMAYIM_NEKUDOTAYIM token if you prefer)
class X {
public static $var = 13;
}
echo X::$var;
Variable variables are supported here, too:
$class = 'X';
echo $class::$var;
You should understand what the static property means. Static property or method is not for the objects. They are directly used by the class.
you can access them by
Class_name::static_property_name
These days, there is a pretty simple, clean way to do this.
<?php
namespace Foo;
class Bar
{
public static $baz=1;
//...
public function __toString()
{
return self::class;
}
}
echo Bar::$baz; // returns 1
$bar = new Bar();
echo $bar::$baz; // returns 1
You can also do this with a property in PHP 7.
<?php
namespace Foo;
class Bar
{
public static $baz=1;
public $class=self::class;
//...
}
$bar = new Bar();
echo $bar->class::$baz; // returns 1
class testClass {
public static $property = "property value";
public static $property2 = "property value 2";
}
echo testClass::$property;
echo testClass::property2;
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
I want to access private methods and variables from outside the classes in very rare specific cases.
I've seen that this is not be possible although introspection is used.
The specific case is the next one:
I would like to have something like this:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
This method should be able to be injected in the code like this:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)
So...
If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:
> $this->myPublicMethod();
But you cannot run successfully the second one:
> $this->myPrivateMethod();
Do any of you have any idea, or if there is any library for PHP that allows you to do this?
Thanks a lot!
Just make the method public. But if you want to get tricky you can try this (PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
EDIT:
Updated to include examples of private function calls with parameters.
As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.
The Closure class
For example we have a class with a private variable and we want to access it outside the class:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.
EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.
That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.
A code sample (though I haven't tested it, so there may be errors) might look like
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Here's a variation of the other answers that can be used to make such calls one line:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie
private function _myPrivateMethod()
Then i simply make the function public.
public function _myPrivateMethod()
So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.
If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.
One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.
I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>