PHP namespace with Dynamic class name - php

Wondering if anyone else has encountered this problem when utilizing the new ability to namespace classes using PHP 5.3.
I am generating a dynamic class call utilizing a separate class for defining user types in my application. Basically the class definer takes an integer representation of types and interprets them, returning a string containing the classname to be called as the model for that user.
I have an object model for the user's type with that name defined in the global scope, but I have another object with the same name for the user's editor in the Editor namespace. For some reason, PHP won't allow me to make a namespaced dynamic call as follows.
$definition = Definer::defineProfile($_SESSION['user']->UserType);
new \Editor\$definition();
The identical syntax works for calling the global basic object model in the global namespace and I use it this way reliably throughout the application.
$definition = Definer::defineProfile($_SESSION['user']->UserType);
new $definition();
This will correctly call the dynamically desired class.
Is there a reason the two would behave differently, or has dynamic calling for namespaces not been implemented in this manor yet as this is a new feature? Is there another way to dynamically call a class from another namespace without explicitly placing its name in the code, but from within a variable?

Well, just spell out the namespace in the string:
$definition = Definer::defineProfile($_SESSION['user']->UserType);
$class = '\\Editor\\' . $definition;
$foo = new $class();
And if it's a child namespace (as indicated in the comments), simply prepend the namespace with __NAMESPACE__:
$class = __NAMESPACE__ . '\\Editor\\' . $definition;
So if the current namespace is \Foo\Bar, and $definition is "Baz", the resulting class would be \Foo\Bar\Editor\Baz

Related

Fatal error while extending a class which does not have namespace

I have two classes, Database and States. The class Database has no namespace assigned. The class States, written in file states.php, has a namespace assigned as below:
namespace Resources;
require_once 'database.php';
$states = new States();
echo $states->readAll();
class States extends Database{
private $db;
public function __construct(){
$this->db = new Database();
}
function readAll(){
return $this->db->Execute('SELECT * FROM states;');
}
}
If I enter the url http://localhost/mydomain/objects/states.php which should instantiate the class and show list of states, an error is thrown as:
Fatal error: Uncaught Error: Class 'Resources\Database' not found in
C:\xampp\htdocs\mydomain\objects\states.php on line 5
If I remove the line namespace Resources; the code runs.
I have recently decided to implemen namespaces in my website, so most likely, I am doing something wrong.
Any help please?
The PHP manual has a section introducing namespaces which is well worth reading. In particular, have a look at this page drawing the analogy to a file system:
The same principle can be applied to namespaced elements in PHP. For
example, a class name can be referred to in three ways:
Unqualified name, or an unprefixed class name like $a = new foo(); or foo::staticmethod();. If the current namespace is currentnamespace,
this resolves to currentnamespace\foo. If the code is global,
non-namespaced code, this resolves to foo.
Qualified name, or a prefixed class name like $a = new subnamespace\foo(); or subnamespace\foo::staticmethod();. If the
current namespace is currentnamespace, this resolves to
currentnamespace\subnamespace\foo. If the code is global,
non-namespaced code, this resolves to subnamespace\foo.
Fully qualified name, or a prefixed name with global prefix operator like $a = new \currentnamespace\foo(); or
\currentnamespace\foo::staticmethod();. This always resolves to the
literal name specified in the code, currentnamespace\foo.
In your example, Database is an "unqualified name", so point 1 applies. The current namespace is Resources, so it refers to Resources\Database. If you remove the namespace Resources; line, the code becomes "global, non-namespaced code", so it refers to just Database.
To refer to the class Database when the current namespace is Resources, you can use a "fully qualified name", as described in point 3. So in this case, you would write class States extends \Database.
There are other ways to write it, such as adding use statements to import/alias a name, but there's no point me copying the whole PHP manual here.

Dynamic namespaced class with alias

SO,
I have an issue with dynamic object creation using namespaces.
Here's namespace code:
namespace Foo
{
class Bar
{
}
}
Now, I'm trying to create object of class Bar with:
include('namespace.php');
$sName = 'Bar';
$sClass = '\\Foo\\'.$sName;
$rObj = new $sClass; //correct object
and everything going well with that. But, now I want to use alias and doing something like:
include('namespace.php');
use Foo as Baz;
$sName = 'Bar';
$sClass0= '\\Foo\\'.$sName;
$sClass1= '\\Baz\\'.$sName;
$rObj = new $sClass0; //correct object
$rObj = new $sClass1; //Fatal error
And I'm unable to instantiate an object such way (and accessing via full name still works well).
So, my question is - is it possible to access the class via alias somehow, and, if yes, how? I've also tried to access when using $sClass1='Baz\\'.$sName - no success. Also, I've checked declared classes via get_declared_classes() function, it shows that I have only \Foo\Bar class (no reference to an alias).
I'm not sure if it matters, but I'm using PHP 5.5 version.
Only the parser uses your namespace aliases to canonicalize the class references inside each of your files.
In other words, it doesn't introduce some kind of global alias that other code can use. Once your script has been parsed, the alias is no longer used.
This behaviour is also described in the manual:
Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.

PHP Problems with constructing classes (variables and namespaces)

I just got stuck with the following problem. I'm trying to construct a class but it isn't working. When I'm constructing the class it uses namespaces and variables, because the variable has to be put behind a backslash (for the namespace) it gives an error.
Here's an example code of defining the class;
$className = 'Help';
$controller = new \controller\$className;
The class name is defined in a variable, in the example code above I've just set it to 'Help'. When constructing the class it has \controller\ in front of it, that's cause it's in that namespace. If I remove the namespace thing away so it just has;
$controller = new $className;
it does work. The problem is probably caused because there's a backslash in front of the variable which contains the class name to construct. I am not able to add use controller; in the beginning of the code because the file containing the class is loaded inside the constructor, and the class is immediately constructed after the file has been loaded. The use function could only be used in the beginning of your file, not inside a method, I think.
I hope someone could help me out,.
Thanks in advance,
Tim Visée
Your first example is invalid syntax. You would need instead something like:
$className = '\controller\Help';
$controller = new $className();
Set the fully qualified class name to a variable and use that to instantiate a new object:
$className = '\controller\Help';
$controller = new $className;

To store as a class parameter or normal php variable

I am new to OO concepts in PHP. I have a class called MY_ controller which is my base class. All classes extend this class. I am using MVC architecture. I am using caching in my system now. So i load the cache variable in the constructor of my base class. I use normal php variable like $cacheVariable in my function to store the value from cache. I was wondering if it would serve any help if i store it as a class parameter and use like $this->cacheVariable? In each function i get cache value like $this->cache->get('cacheVariable'); will it help if i get value from $this->cacheVariable
If you want to be able to use $cacheVariable anywhere else besides your constructor you'll want to use $this
public function __construct() {
//...
$this->cacheVariable = $this->cache->get('cacheVariable');
//...
}
Also remember, if you want your children classes to inherit this variable from your base class you will need to set it as either public or protected. If it's private children will not inherit it.
When you say "class variable" I assume you are referring to a property (property of an instance=. Note the difference:
if you have a class, say MyClassA, then in your scripts you will instantiate that class using the operator new (depending on your PHP version you can use a different constructor syntax it changed since PHP-5.3.0):
<?php
class MY_controller{
public $cacheVariable;
// constructor
function MY_controller($aValue){
// constructor code which loads cacheVariable, for example with parameter
$this->cacheVariable = $aValue;
}
public function someFunction(){
//... some code, then access the property
$cv = $this->cacheVariable;
}
}
$aController = new MY_controller(42);
?>
As you inherit from MY_controller, every instance of that class, will have access to cacheVariable through $this->cacheVariable.
The important thing I wanted to clarify is that it is an instance property, not a class one. For further reference on OOP in PHP, refer to the properties section in PHP's OOP manual and the inheritance section.
When you instantiate only one instances of your controller (derived from your main controller), its a conceivable solution.
In my opinion the better idea is getting variable directly from cache service everywhere you want in your class and don't keep it as a class property. The reason is simple: let's say value of some key from cache will be changed (or expires) in the other place than your class. If you have this value as class property you need to keeping eye on it every time you access this value but if you retrieving it from cache you just don't care (because the cache cares if value of some key doesn't changed or expired).

PHP Namespaces & Referencing Classes not contained within Namespaces

I have a simple question, which should hopefully have a quick answer. The code I have written makes heavy use of namespaces (I use fully qualified names everywhere); however, a piece of code (a calendar / date picker control, not written by myself) needs to be included. When I attempt to create the control, it assumes the current namespace (GUI), resulting in this error: "PHP Fatal error: Class 'GUI\tc_calendar' not found in C:\inetpub\wwwroot\Calico\calico_classes_v2.php on line 1852". Now, the calendar control itself (and it's underlying class file) does not make use of namespaces, and I am a little worried about attempting to modify it (an earlier attempt did not go well).
How can I import / include a control, that is not contained within a namespace, into the rest of my code, that does? Does PHP have something like "Import class calendar from file AS \Calendar\Calendar"?
Edit:
For additional information: I have a class, called "tc_calendar", contained in a file called "tc_calendar.php". It is not part of any namespace.
In a separate file, I have several classes (Bitmap, CompositeCalendar, EventEditor, TimeExtractor), all contained within their appropriate namespaces (GUI, Data, Extract, etc.).
In one of those classes, CompositeCalendar, contained within the GUI namespace, I am trying to create an instance of a tc_calendar. However, PHP is throwing an error (above). tc_calendar is not a part of any namspace (and definitely not a part of the GUI namespace, which PHP is just assuming, because it can't seem to find it), and I need help creating an instance of it.
tldr; $newcontrol = new tc_calendar() doesn't work; PHP tries to guess the namespace for it (because one isn't specified, because tc_calendar isn't a part of any namespace), comes up with \GUI\tc_calendar (obviously wrong). How do I access a class, not contained within a namespace, from inside a namespace?
Do you mean something like this:
namespace GUI;
use \tc_calendar as Calendar;
$myCalendar = new Calendar();
The as Calendar is optional. You could aswell keep it with the original name tc_calendar if you ommit the as Calendar.
Update
To put it in shape of the comment:
namespace {
class tc_calendar {}
}
namespace GUI {
use \tc_calendar;
class CompositeCalendar {
private function blah() {
$control = new tc_calendar();
$control->stuff();
}
}
}
I wouldn't copy paste external libraries into he same file though. It bad practise. It is better to keep them in another file and then include them and have the following:
namespace GUI;
use \tc_calendar;
require_once 'tc_calendar.php';
class CompositeCalendar {
private function blah() {
$control = new tc_calendar();
$control->stuff();
}
}
Or combine my 3 snippets to have it any other form you like.
Also I would suggest to extend the calendar if you are just building calendar class based on the the tc_calendar:
namespace GUI;
use \tc_calendar;
require_once 'tc_calendar.php';
class CompositeCalendar extends tc_calendar {
private function blah() {
$this->stuff();
}
}
Any class not in a namespace is automatically in the global namespace.
To refer to anything in the global namespace from anywhere, use a single preceding \:
new \tc_calendar;

Categories