I'd like to get the class/included variables/elements when I included a php file/class, somehow maybe I should try reflection to do that? If so, how?
For instance, I'd have a PHP class called foo.php:
<?php
class foo
{
public function bar()
{
return "foobar";
}
}
?>
then, in bar.php, I would like to:
<?php
class bar
{
public function foo()
{
$included_resources = include("foo.php"); // Notice, $included_resources is an array
if (($key = array_search("foo", $included_resources)) != false) // "foo" can be any variable or class name
return $included_resources[$key]->bar();
}
}
$helloworld = new bar();
echo $helloworld->foo();
?>
Result: a string value of "foobar" will be represented on the screen
First, store the declared variables in an array before including a file. Then do the include. Then store the declared variables in another array again. Then simply check the difference:
$declared_vars_before = get_defined_vars();
include 'another_file.php';
$declared_vars_after = get_defined_vars();
foreach ($declared_vars_after as $value) {
if (!in_array($value, $defined_vars_before)) {
echo $value . '<br>';
}
}
Same with classes, but use get_declared_classes instead of get_defined_vars.
Related
I'm having an issue calling a variable thats included in a class. What am I missing here? Thank you in advance for the support. Very much appreciated.
//index2.php
$var2 = 'var2';
//index.php
class something {
__construct() {
include('index2.php');
}
}
$run_it = new something();
echo $run_it->var2; //how do I call var2?
You could do this. Kind of a strange way to do things but here goes:
index.php
<?php
class something{
function __construct() {
include('index2.php');
}
}
//s1
$s1 = new something();
$s1->var2 = 'var2 changed';
//s2
$s2 = new something();
//print em out
print_r($s1);
print_r($s2);
index2.php
<?php
$this->var2 = 'var2'; //$this pseudo-variable works because we're including index2.php within the scope of our class instance
?>
Output
$ php a.php
something Object
(
[var2] => var2 changed
)
something Object
(
[var2] => var2
)
You cannot extend property's of a class with including files. The class is defined as it is written. You have the following ways to add code to a class dynamically.
Extend a class.
Use traits (copy pasting functions into a class)
Use magic methods (__call, __get, __set)
This example will print variables defined in the global scope (like your example) as you wanted it to do.
However, this is not the way it should be used and I suggest finding a different method of writing your class.
include 'somefile.php'; // <?php $var3 = 'testing' ?>
class foo{
public $var2 = 'var2'; # should be declared within the class.
public function __get($name){
// property 'var3' is not defined in the class so this method is magically called instead.
if(isset($GLOBALS[$name])){
return $GLOBALS[$name]; // Here we return the value $var3 defined in the global scope.
} else {
trigger_error("Call to undefined variable '$name'");
}
}
public function __construct(){ # Missed function statement.
echo 'hello';
}
}
$c = new foo();
echo $c->var3; // testing
If your index2.php contains this:
$var2 = 'var2';
Then you can include that file to get access to $var2. You can then pass that variable to your something constructor as an argument:
//index.php
class something {
public $var2;
public function __construct($arg) {
$this->var2 = $arg;
}
}
include 'index2.php';
$run_it = new something($var2);
echo $run_it->var2; // echos 'var2'
It's obvious there are other ways to do something like what you're attempting to do (there is usually more than one way to do most things), but really the most sensible way to get external data into your object is to pass it via constructor arguments.
If you don't do this, the class will forever depend on some other file existing in the correct location relative to the class or calling file, with all of the correct variables set in it. If that file is altered or moved, objects of that class may not function properly if they can even be instantiated at all.
I agree with Xorifelse, you can do it with traits. example.
fields.php
trait Aa {
public $fields = [
"name"=>"string->5",
"number"=>"integer->3",
];
}
traits.php
include('fields.php');
class ABC {
use Aa;
public function __set($field,$value)
{
if(array_key_exists($field,$this->fields))
{
$this->fields[$field] = $value;
}
else
{
$this->fields[$field] = null;
}
}
public function __get($field)
{
if(array_key_exists($field,$this->fields))
{
return $this->fields[$field];
}
else
{
return null;
}
}
}
$a = new ABC();
$a->number = 111;
var_dump($a->fields);
array(2) {
["name"]=>
string(9) "string->5"
["number"]=>
int(111)
}
var_dump($a->number);
int(111)
You can take advantage of get_defined_vars. Assuming your variables are in a file (e.g. filevars.php):
filevars.php
<?php
$name = 'myName';
$address = 'myAddress';
$country = 'myCountry';
$phones = array('123456789','987654321');
?>
You can add a method to your class (getVars) and define a property (vars) that wraps all variables existing in filevars.php:
class-test.php
<?php
class Test
{
public $vars;
function getVars()
{
include ('filevars.php');
$this->vars = get_defined_vars();
}
}
?>
Usage
<?php
include ('class-test.php');
$myClass = new Test();
$myClass->getVars();
print_r($myClass->vars);
?>
Output:
Array
{
[name] => myName
[address] => myAddress
[country] => myCountry
[phones] => Array
{
[0] => 123456789
[1] => 987654321
}
}
You can also refer any individual included variable, e.g.:
echo $myClass->vars['country']; // myCountry
Is it possible to get the line and file where a object is created?
For example.
I know the print PHP error outputs where a error occurred and at which line. Is it possible to use that mechanism?
Sending the file to the object is easy. I can just use basename(__FILE__) as an argument. But I would prefer if the object arguments can remain empty. Like this:
Foo.php
<?php
class Foo {
public $line = null;
public function __construct(){
$this->line = where_object_is_assigned
}
}
?>
Index.php
<?php
$object = new Foo();
echo $object->line // Output Index.php line 3
?>
Is there a way for the object to access this data without sending it?
Thanks in advance
I solved it by using the function debug_backtrace();
<?php
class Foo {
public $line = null;
public function __construct(){
$bt = debug_backtrace();
$caller = array_shift($bt); // Get first array
$this->line = $caller["line"];
}
}
?>
Index.php
<?php
$object = new Foo();
echo $object->line // Output: 3
?>
The function must be used in __construct() else it won't work.
Read more here: http://php.net/manual/en/function.debug-backtrace.php
This will output on which line-number the object is created
Class
class Foo {
public $line = NULL;
public function __construct($line){
$this->line = $line;
}
}
Index.php
<?php
$object = new Foo(__LINE__); //Will output 1
echo $object->line;
PHP provides a large number of predefined constants to any script which it runs. Within this you can simply find the predefined constant named as LINE
__LINE__ The current line number of the file.
So you need to simply use the predefined constant within your code like as
<?php
class Foo {
public $line = __LINE__;
}
$object = new Foo();
echo $object->line;
?>
Is there anyway I can unset (and set a new value) for a variable in a core class of a script without touching the core code?
This is how the value of the variable set in the class:
class MyClass {
var $myvar = 'value';
...
...
}
I tried this, but didn't worked;
function unset_myvar($myvar) {
unset($myvar);
$myvar = 'newvalue';
return $myvar;
}
Thanks
Instead:
$myvar = 'newvalue';
you are looking for
$this->myvar = 'newvalue';
You are asking elementary question, so I suggest instead of just copying lines from my answer, you now head to PHP.net and read manual about PHP fundamentals
Try this:
class MyClass {
var $myvar = 'value';
function unset_myvar($myvar) {
unset($this->myvar);
$this->myvar = $myvar;
return $this->myvar;
}
}
So, now you can creat and object and unset variable and set another value to it:
$obj = MyClass ();
$obj = unset_myvar('someValue');
Simply:
class MyClass {
public $myvar = 'value';
...
...
}
$obj = new MyClass();
unset($obj->myvar);
The following code prints the value which was assigned , unsets the variable and then sets a new value to the variable.
<?php
class MyClass {
var $myvar = 'value';
public function dispvar()
{
echo $this->myvar;
}
public function destroyvar()
{
unset($this->myvar);
}
public function setvar($param)
{
$this->myvar=$param;
}
}
$a = new MyClass();
$a->dispvar(); //"prints" value
$a->destroyvar();
$a->dispvar(); //"prints" nothing !!
$a->setvar('blabla');
$a->dispvar(); //"prints" blabla
Demo
[FINAL EDIT]
Seems like I've been missing an important Warning contained in Variables variable PHP Manual
http://www.php.net/manual/en/language.variables.variable.php :
Please note that variable variables cannot be used with PHP's Superglobal arrays within functions or class methods. The variable $this is also a special variable that cannot be referenced dynamically.
[ORIGINAL QUESTION]
I've encountered a problem trying to set/get html/server variables $_POST, $_GET, $_SESSION etc.. dynamically using a variable to hold it's name :
// Direct name
${'_GET'}['test'] = '1';
// Variable-holded name
$varname = '_GET';
${$varname}['test'] = '2';
echo "value is " . $_GET['test'];
will output :
value is 1
any idea why?
[EDIT 1]
This is why I want to use it this way :
class Variable {
protected static $source;
public function __get($key) {
// Some validation / var manip needed here
if ( isset( ${self::$source}[$key] ) ) {
return ${self::$source}[$key];
}
}
public function __set($key, $value) {
// Some validation / var manip needed here too
${self::$source}[$key] = $value;
}
}
final class Get extends Variable {
use Singleton;
public static function create() {
parent::$source = "_GET";
}
}
final class Post extends Variable {
use Singleton;
public static function create() {
parent::$source = "_POST";
}
}
final class Session extends Variable {
use Singleton;
public static function create() {
parent::$source = "_SESSION";
}
}
create is called in the singleton constructor when instanciated
[EDIT 2] using PHP 5.4.3
I'm guessing it has something to do with the fact that you shouldn't be assigning values to $_GET like that. Anyhow, this works just fine:
$source = '_GET';
echo ${$source}['test'];
// URL: http://domain.com/thing.php?test=yes
// output: "yes"
edit
Coincidentally, today I went back to update some old code where it looks like I was trying to implement exactly this inside of a class, and it wasn't working. I believe that using the global keyword before attempting to access a superglobal via a variable variable will solve your problem as well.
Class MyExample {
private $method = '_POST';
public function myFunction() {
echo ${$this->method}['index']; //Undefined index warning
global ${$this->method};
echo ${$this->method}['index']; //Expected functionality
}
}
You may be looking for variable variables. Taken from PHP.net:
<?php
$a = 'hello';
?>
<?php
$$a = 'world';
?>
<?php
echo "$a ${$a}";
//returns: hello world
//same as
echo "$a $hello";
?>
EDIT
Another user on php.net had your exact question. Here is his answer.
<?php
function GetInputString($name, $default_value = "", $format = "GPCS")
{
//order of retrieve default GPCS (get, post, cookie, session);
$format_defines = array (
'G'=>'_GET',
'P'=>'_POST',
'C'=>'_COOKIE',
'S'=>'_SESSION',
'R'=>'_REQUEST',
'F'=>'_FILES',
);
preg_match_all("/[G|P|C|S|R|F]/", $format, $matches); //splitting to globals order
foreach ($matches[0] as $k=>$glb)
{
if ( isset ($GLOBALS[$format_defines[$glb]][$name]))
{
return $GLOBALS[$format_defines[$glb]][$name];
}
}
return $default_value;
}
?>
Why not just use $_REQUEST which includes $_GET, $_POST and $_COOKIE? Or am I misunderstanding the purpose?
When I use this function variables created by the included scripts are retained within the scope of this function.
function reqscript($script)
{
$include_dir = 'inc/';
$page_ext = '.php';
include($include_dir.$script.$page_ext);
}
Is there any way of me not having to use the following method?
include(buildfilename('...'));
If you want to define some variables in your included file, you have to use $GLOBALS.
e.g: $foobar = 42; should be $GLOBALS['foobar'] = 42;
So $foobar is available in the global scope (outside of functions).
But I would prefer a buildfilename() method.
Your answer is on php.net already, use return at the end of your included file.
http://php.net/manual/en/function.include.php
Example #5:
return.php
<?php
$var = 'PHP';
return $var;
?>
noreturn.php
<?php
$var = 'PHP';
?>
testreturns.php
<?php
$foo = include 'return.php';
echo $foo; // prints 'PHP'
$bar = include 'noreturn.php';
echo $bar; // prints 1
?>
I suggest you adopt your code to use the buildfilename() method, like Floem suggested. However, if you can't or do not wish to do so, here's a simple wrapper to import variables to the global namespace:
class Req {
public function __construct($src) {
include($src);
foreach (get_object_vars($this) as $name => $value) {
$_GLOBALS[$name] = $value;
}
}
}
function reqscript($script) {
$include_dir = 'inc/';
$page_ext = '.php';
new Req($include_dir . $script . $page_ext);
}