Use variable as namespace - php

In some other file (someusername\classes\MyClass for instance), I have
<?php
namespace someusername;
class MyClass
{
static function Test()
{
echo "working";
}
}
?>
I have stumbled across an annoying little barrier:
<?php
$user = "someusername";
$class = "MyClass";
require_once "$user\\classes\\$class";
//This line should be the equivalent of 'use someusername as User;'
use $user as User; //Parse Error: syntax error, unexpected '$user'
$c = "User\\$class";
$UserSpecificClass = new $c();
?>
I can get around it via the following, but the use statement would make things a lot nicer
<?php
$user = "someusername";
$class = "MyClass";
require_once "$user\\classes\\$class";
$c = "$user\\$class";
$UserSpecificClass = new $c();
?>
Is it possible to use variables in use statement in PHP? Or is it better to avoid the use statement with this approach?

Importing is performed at compile-time.
Assigning the variable is done at run-time after compilation, at which point any import should already be imported.
So this is not possible. Best solution would indeed be to use the FQN in a string and initialize that.
$c = "$user\\$class";
$UserSpecificClass = new $c();

Related

Can I use a string variable to initialize a class in PHP?

I'd like to use a string variable to initialize an object. Is something like this possible?
$class = "MyClass";
$x = new $class();
return $x;
Edit: Ha, so when I tried to test this and it didn't work I had a syntax error somewhere else in my script. Apparently this works just fine. Neat.
Yes. Its possible in PHP.
$className = 'MyClass';
$object = new $className;
Attaching PHP documentation snippet on new operator

Instantiating a PHP class using a variable is not working

This is working:
$x = new classname();
This is not working:
$class = "classname";
$x = new $class();
The error I get is "Class classname not found". PHP version is 5.4.22. Any ideas? As far as I have researched into this topic this is exactly what you need to do in order to instantiate a class using a variable.
My actual testcode (copy+paste), $build = 1:
//include the update file
$class="db_update_" . str_pad($build, 4, '0', STR_PAD_LEFT);
require_once(__ROOT__ . "/dbupdates/" . $class . ".php");
$x = new db_update_0001();
$xyz="db_update_0001";
$x = new $xyz();
The class definition:
namespace dbupdates;
require_once("db_update.php");
class db_update_0001 extends db_update
{
...
}
I just found out that my editor added
use dbupdates\db_update_0001;
to the file. So that explains why "new db_update_0001();" is working. What i want to achieve is that I dynamically include database updates which are stored in files like dbupdates/db_update_0001.php
Regards,
Alex
You have to use the full qualified class name. Which is namespace\classname. So in your case the code should be:
$x = new db_update_0001();
$xyz="dbupdates\db_update_0001";
$x = new $xyz();
The use statement is useless if you like to instantiate a class by using a variable as classname.
Try this
<?php
$className = yourClassName();
$x = new $className;
?>

Can PHP namespaces contain variables?

Can PHP namespaces contain variables? If so, how can this be accomplished?
No. You can set a variable after declaring a namespace, but variables will always exist in the global scope. They are never bound to namespaces. You can deduce that from the absence of any name resolution descriptions in
FAQ: things you need to know about namespaces (PHP 5 >= 5.3.0)
There would also be no allowed syntax to locate variables in a namespace.
print \namespace\$var; // syntax error
print "${namespace\\var}"; // "unexpected T_NS_SEPARATOR"
Try this
<?php
namespace App\login;
$p = 'login';
$test2 = '\App\\'.$p.'\\MyClass';
$test = new $test2;
No they cannot, as mario said.
To encapsulate variables use Classes. Polluting the global variable space should definitely be avoided.
Example
class_dbworker.php:
class DbWorker
{
//properties and method logic
}
class DbWorkerData
{
public static $hugerelationsmap = array(....);
public static ....
}
mainapp.php:
include_once 'class_dbworker.php';
print_r( DbWorkerData::$hugerelationsmap );
Example using namespaces
class_dbworker.php:
namespace staticdata;
class DbWorker
{
//properties and method logic
}
class DbWorkerData
{
public static $hugerelationsmap = array(....);
public static ....
}
mainapp.php:
include_once 'class_dbworker.php';
use staticdata as data;
print_r( \data\DbWorkerData::$hugerelationsmap );
It is not possible because $MYVARNAME is still in the global scope. Try following code.
namespace.php
<?php
namespace MYNAME;
use MYNAME as M;
const MYVAR = 'MYVARNAME';
${M\MYVAR} = date('Y');
echo $MYVARNAME; // PRINT YEAR
$MYVARNAME = 'X';
echo $MYVARNAME; // PRINT X
echo ${M\MYVAR} ; // PRINT X
include('file.php');
?>
file.php
<?php
${MYNAME\MYVAR}=date('Y');
echo $MYVARNAME; // PRINT YEAR
$MYVARNAME = 'X';
echo $MYVARNAME; // PRINT X
echo ${MYNAME\MYVAR}; // PRINT X
include('file2.php');
?>
file2.php
<?php
namespace MYNAME2;
use MYNAME2 as N;
const MYVAR = 'MYVARNAME';
${N\MYVAR} = 'Y';
echo $MYVARNAME; // PRINT Y
echo ${MYNAME\MYVAR}; /* PRINT Fatal error: Uncaught Error:
Undefined constant 'MYNAME2\MYNAME\MYVAR' */
?>
You can bound a variable to the namespace by wrapping the variable inside a function.
<?php
namespace furniture;
// instead of declaring a $version global variable, wrap it inside a function
function version(){
return "1.3.4";
}
?>
It can be done - sort of.
This is probably extremely bad and should never be done, but it is possible by using variable variables, and the magic constant for namespace.
So a string-variable to name the variable we want to use, like so:
<?php
namespace your\namespace;
$varname = __NAMESPACE__.'\your_variablename'; //__NAMESPACE__ is a magic constant
$namespaced_variable = $$varname; //Note the double dollar, a variable variable
?>
Store Complete classPath in Variable and use after 'new'.
It is very important to realize that because the backslash is used as an escape character within strings, it should always be doubled when used inside a string.
<?php
$a = "namespace\\className"; // 'which will print namespace/className'
$obj = new $a;
?>
Alternate ways that can make code more organized:
Instead of like \view\header\$links:
(1) Backslashes in array key for imaginary nesting,
Example:
$myVar['view\header\links'] = 'value';
// OR use multidimentional arrays
$view['header']['links'] = 'value';
(1.1) Use Global Array, Example
// START - SETUP
define('I', 'mySite_19582730');
// END - SETUP
// Usage:
$GLOBALS[I]['view\header\links'] = 'value';
// OR
$GLOBALS[I]['view__header__links'] = 'value';
(1.1.1) Functions to get & set value in Global Array
function set($key, $val){
if (is_string($key)) $GLOBALS['site_8619403725'][$key] = $val;
elseif (is_array($key)){
foreach($key as $ky => &$vl) {
$GLOBALS['mySite_19582730'][$vl] = $val;
}
}
}
function get($key){
return # $GLOBALS['mySite_19582730'][$key];
}
// Usage
set('view\header\search','<div></div>');
set(['view\header\logo','view\header\homeLink'], '');
get('view\header\search');
(2) Use __ (double underscores) in variable name to make imaginary nesting,
Example:
$view__header__links = 'value';

run function block in context of global namespace in PHP

So the senario is that I want to have a custom function for requiring libraries. Something like:
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
}
The problem being that require and require_once will load the files into the namespace of the function, which doesn't help for libraries of functions, classes, et cetera. So is there a way to do this?
(Something avoiding require and require_once altogether is fine, as long as it doesn't use eval since it's banned on so many hosts.)
Thanks!
Technically include() is meant to act as though you're inserting the text of included script at that point in your PHP. Thus:
includeMe.php:
<?php
$test = "Hello, World!";
?>
includeIt.php:
<?php
include('includeMe.php');
echo $test;
?>
Should be the exact same as:
<?php
/* INSERTED FROM includeMe.php */
$test = "Hello, World!";
/* END INSERTED PORTION */
echo $test;
?>
Realizing this, the idea of making a function for dynamically including files makes about as much sense (and is about as easy to do) as having dynamic code all-together. It's possible, but it will involve a lot of meta-variables.
I'd look into Variable Variables in PHP as well as the get_defined_vars function for bringing variables into the global scope. This could be done with something like:
<?php
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$prev_defined_vars = get_defined_vars();
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
$now_defined_vars = get_defined_vars();
$new_vars = array_diff($now_defined_vars, $prev_defined_vars);
for($i = 0; $i < count($new_vars); $i++){
// Pull new variables into the global scope
global $$newvars[$i];
}
}
?>
It may be more convenient to just use require() and require_once() in place of e_load()
Note that functions and constants should always be in the global scope, so no matter where they are defined they should be callable from anywhere in your code.
The one exception to this is functions defined within a class. These are only callable within the namespace of the class.
EDIT:
I just tested this myself. Functions are declared in the global scope. I ran the following code:
<?php
function test(){
function test2(){
echo "Test2 was called!";
}
}
//test2(); <-- failed
test();
test2(); // <-- succeeded this time
?>
So the function was only defined after test() had been run, but the function was then callable from outside of test(). Therefore the only thing you should need to pull into the global scope are your variables, via the script I provided earlier.
require_once E_ROOT.$libName.'.php';
KISS
Instead of doing this...
$test = "Hello, World!";
... you could consider doing this ...
$GLOBALS[ 'test' ] = "Hello, World!";
Which is safe and consistent in both local function context, and global include context. Probably not harmful to visually remind the reader that you are expecting $test to become global. If you have a large number of globals being dragged in by your libraries maybe there's justification for wrapping it in a class (then you have the benefit of spl_autoload_register which kind of does what you are doing anyhow).

Issue with assigning class variable in PHP

I am trying to assign a variable to a class in PHP, however I am not getting any results?
Can anyone offer any assistance? The code is provided below. I am trying to echo the URL as shown below, by first assigning it to a class variable.
class PageClass {
var $absolute_path = NULL;
function get_absolute_path(){
$url = $this->absolute_path;
echo $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
$page->get_absolute_path(); //this should echo the URL as defined above - but does not
It also works for me.
Take a look at a live example of your code here.
However, there are a few things you should change about your class.
First, Garvey does make a good point that you should not be using var. That's the older PHP4, less OOP conscious version. Rather declare each variable public or private. In fact, you should declare each function public or private too.
Generally, most classes have private variables, since you usually only want to change the variables in specific ways. To achieve this control you usually set several public methods to allow client functions to interact with your class only in restricted predetermined ways.
If you have a getter, you'd probably want a setter, since these are usually used with private variables, like I described above.
A final note is that functions named get usually return a value. If you want to display a value, it is customary to use a name like display_path or show_path:
<?php
class PageClass
{
private $absolute_path = NULL;
public function set_absolute_path($path)
{
$this->absolute_path = $path;
}
public function display_absolute_path()
{
echo $this->absolute_path;
}
}
$page = new PageClass();
$page->set_absolute_path("http://localhost:8888/smile2/organic/");
$page->display_absolute_path();
// The above outputs: http://localhost:8888/smile2/organic/
// Your variable is now safe from meddling.
// This:
// echo $this->absolute_path;
// Will not work. It will create an error like:
// Fatal error: Cannot access private property PageClass::$absolute_path on ...
?>
Live Example Here
There's a section on classes and objects in the online PHP reference.
class PageClass {
public $absolute_path = NULL;
function get_absolute_path(){
$url = $this->absolute_path;
return $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
echo $page->get_absolute_path();
Works fine for me.
Have you checked that the script and esp. the code in question is executed at all?
E.g. add some unconditional debug-output to the script. Or install a debugger like XDebug to step through the code and inspect variables.
<?php
class PageClass {
var $absolute_path = NULL; // old php4 declaration, see http://docs.php.net/oop5
function get_absolute_path() { // again old php4 declaration
$url = $this->absolute_path;
echo "debug: "; var_dump($url);
echo $url;
}
}
$page = new PageClass();
$page->absolute_path = "http://localhost:8888/smile2/organic/";
echo "debug: page->get_absolute_path\n";
$page->get_absolute_path();

Categories