PHP import classes with use keywords - php

I don't use so far PHP use word, but must now... :)
index.php content:
require_once 'Classes/MainClass.php';
$obj = new Main();
echo $obj->test();
Classes/MainClass.php
<?php
use AdminFrontEnd;
class Main {
function test(){
return new AdminFrontEnd("debug");
}
}
AdminFrontEndClass.php content:
<?php
class AdminFrontEnd {
function __constuctor($test){
echo $test;
}
}
and final, following error:
Fatal error: Class 'AdminFrontEnd' not found in Classes/MainClass.php
on line 10

As per comment from #deceze, you will either need to explicitly import the additional class, using a require statement, or autoload.
The use statement is for aliasing a class, and as #deceze said, can be used to pull in a class from a different namespace, or to avoid a class conflict.
Having a class called 'Main' may not be ideal. Is it a singleton, or will there be multiple 'Main's? Maybe this class would be better named 'App'.
In the longer term you will want to learn about using namespaces, so that if you use other people's classes and plugins, you won't have conflict. I've added a solution, and also some broader info below.
To get you off the hook:
Classes/MainClass.php
<?php
require_once 'Classes/AdminFrontEnd.php';
class Main { /* etc... */
Further reading I would recommend:
Examples for creating an autoload:
http://php.net/manual/en/language.oop5.autoload.php
You'll probably want to learn about namespaces too:
http://php.net/manual/en/language.namespaces.php
I also highly recommend reading about interoperability coding standards. It's a lot to take in to begin with, but it will help you understand the logic behind using namespaces, and autoloaders.
http://www.php-fig.org/

Related

Why use class aliases?

Why would we use the class_alias function? For example:
Class Test {
public function __construct(){
echo "Class initialized";
}
}
class_alias("Test", "AnotherName");
$instance = new AnotherName(); # equivalent to $instance = new Test();
According to the manual, "The aliased class is exactly the same as the original class."
What is this useful for?
Surprisingly, nobody has mentioned the obvious reason why one would do this: the use keyword can only be used in the outmost scope, and is processed at compile-time, so you can't use Some\Class based on some condition, nor can it be block-scoped:
namespace Foo;
if (!extension_loaded('gd'))
{
use Images\MagicImage as Image;
}
else
{
use Images\GdImage as Image;
}
class ImageRenderer
{
public function __construct(Image $img)
{}
}
This won't work: though the use statements are in the outmost scope, these imports are, as I said before, performed at compile-time, not run-time. As an upshot, this code behaves as though it was written like so:
namespace Foo;
use Images\GdImage as Image;
use Images\MagicImage as Image;
Which will produce an error (2 class with the same alias...)
class_alias however, being a function that is called at run-time, so it can be block scoped, and can be used for conditional imports:
namespace Foo;
if (!extension_loaded('gd'))
{
class_alias('Images\\MagicImage', 'Image');
}
else
{
class_alias('Images\\GdImage','Image');
}
class ImageRenderer
{
public function __construct(Image $img)
{}
}
Other than that, I suspect the main benefit of class_alias is that all code written, prior to PHP 5.3 (which introduced namespaces) allowed you to avoid having to write things like:
$foo = new My_Lib_With_Pseudo_Name_Spaces_Class();
Instead of having to refactor that entire code-base and create namespaces, It's just a lot easier to add a couple of:
class_alias('My_Lib_With_Pseudo_Name_Spaces_Class', 'MyClass');
To the top of the script, along with some //TODO: switch to Namespaces comments.
Another use case might be while actually transferring these classes to their namespaced counterparts: just change the class_alias calls once a class has been refactored, the other classes can remain intact.
When refactoring your code, chances are you're going to want to rethink a couple of things, so a use-case like aichingm suggested might not be too far fetched.
Last thing I can think of, but I haven't seen this yet, is when you want to test some code with a mock object, you might use class_alias to make everything run smoothly. However, if you have to do this, you might aswell consider the test a failure, because this is indicative of badly written code, IMO.
Incidently, just today I came across another use-case for class_alias. I was working on a way to implement a lib, distilled from a CLI tool for use in a MVC based web-app. Some of the classes depended on an instance of the invoked command to be passed, from which they got some other bits and bolts.
Instead of going through the trouble of refactoring, I decided to replace the:
use Application\Commands\SomeCommand as Invoker;
Statements with:
if (\PHP_SAPI === 'cli')
{
class_alias('\\Application\\Commands\\SomeCommand', 'Invoker');
}
else
{
class_alias('\\Web\\Models\\Services\\SomeService', 'Invoker');
}
and, after a quick :%s/SomeCommand/Invoker/g in vim, I was good to go (more or less)
Think of this the other way. There is a library and it contains a class called MySq, as the library moves on in development they think 'oh maybe we should just make one database class' so the rewrite the class and call it 'DatabaseConnection' it has the same functions as the MySql class but it can also handle Sql and MsSql. As time goes on and they release the new version 'PHPLib2'. The developer has now two options: 1, tell the users to change from MySql to DatabaseConnection or 2, the developer uses
class_alias("DatabaseConnection","MySql");
and just mark the class MySql as deprecated.
tltr;
To keep version compatibility!
It can be used for:
Changing strange class names of ext. scripts/sources (without the need to rewrite the code)
Making class names shorter (the class alias can be used application wide)
Moving classes to another namespace (#tlenss)

Use namespace in global context with autoloader

Due to an external library I have to use namespaces. Since I havn't used namespaces before I realised using a namespace won't work with my __autoload(). The code below will say
Failed to load class Foo\Bar\NamespaceClass, please update the autoloader!
How may I fix this? The Foo class is just a wrapper around the external library.
// This is my autoloaded class file
use Foo\Bar\NamespaceClass;
class Foo
{
public function Bar()
{
$namespaceClass = new NamespaceClass();
}
}
// This is a separate file calling my class "Foo" from global namespace
$myAutoloadedClass = new Foo();
$myAutoloadedClass->Bar();
I don't think you understand how namespaces work. I recommend you to read articles about that, for instance this one on nettuts+.
Furthermore, I recommend you to use the PSR-0 standards. Almost all 3rd-party libraries follow that and they come in with a autoloader which you can use directly.
At last, you said you use an external library. Have you take a look at composer? That a really great tool to help you autoloading, updating and using external libraries. I recommend you to watch the great screencast of KnpUniversity: "The Wonderfull World of Composer"
You should update the autoloader.

How does the keyword "use" work in PHP and can I import classes with it?

I have a file with a class Resp. The path is:
C:\xampp\htdocs\One\Classes\Resp.php
And I have an index.php file in this directory:
C:\xampp\htdocs\Two\Http\index.php
In this index.php file I want to instantiate a class Resp.
$a = new Resp();
I know I can use require or include keywords to include the file with a class:
require("One\Classes\Resp.php"); // I've set the include_path correctly already ";C:\xampp\htdocs". It works.
$a = new Resp();
But I want to import classes without using require or include. I'm trying to understand how use keyword works. I tried theses steps but nothing works:
use One\Classes\Resp;
use xampp\htdocs\One\Classes\Resp;
use htdocs\One\Classes\Resp;
use One\Classes;
use htdocs\One\Classes; /* nothing works */
$a = new Resp();
It says:
Fatal error: Class 'One\Classes\Resp' not found in C:\xampp\htdocs\Two\Http\index.php
How does the keyword use work? Can I use it to import classes?
No, you can not import a class with the use keyword. You have to use include/require statement. Even if you use a PHP auto loader, still autoloader will have to use either include or require internally.
The Purpose of use keyword:
Consider a case where you have two classes with the same name; you'll find it strange, but when you are working with a big MVC structure, it happens. So if you have two classes with the same name, put them in different namespaces. Now consider when your auto loader is loading both classes (does by require), and you are about to use object of class. In this case, the compiler will get confused which class object to load among two. To help the compiler make a decision, you can use the use statement so that it can make a decision which one is going to be used on.
Nowadays major frameworks do use include or require via composer and psr
1) composer
2) PSR-4 autoloader
Going through them may help you further.
You can also use an alias to address an exact class. Suppose you've got two classes with the same name, say Mailer with two different namespaces:
namespace SMTP;
class Mailer{}
and
namespace Mailgun;
class Mailer{}
And if you want to use both Mailer classes at the same time then you can use an alias.
use SMTP\Mailer as SMTPMailer;
use Mailgun\Mailer as MailgunMailer;
Later in your code if you want to access those class objects then you can do the following:
$smtp_mailer = new SMTPMailer;
$mailgun_mailer = new MailgunMailer;
It will reference the original class.
Some may get confused that then of there are not Similar class names then there is no use of use keyword. Well, you can use __autoload($class) function which will be called automatically when use statement gets executed with the class to be used as an argument and this can help you to load the class at run-time on the fly as and when needed.
Refer this answer to know more about class autoloader.
use doesn't include anything. It just imports the specified namespace (or class) to the current scope
If you want the classes to be autoloaded - read about autoloading
Don’t overthink what a Namespace is.
Namespace is basically just a Class prefix (like directory in Operating System) to ensure the Class path uniqueness.
Also just to make things clear, the use statement is not doing anything only aliasing your Namespaces so you can use shortcuts or include Classes with the same name but different Namespace in the same file.
E.g:
// You can do this at the top of your Class
use Symfony\Component\Debug\Debug;
if ($_SERVER['APP_DEBUG']) {
// So you can utilize the Debug class it in an elegant way
Debug::enable();
// Instead of this ugly one
// \Symfony\Component\Debug\Debug::enable();
}
If you want to know how PHP Namespaces and autoloading (the old way as well as the new way with Composer) works, you can read the blog post I just wrote on this topic: https://enterprise-level-php.com/2017/12/25/the-magic-behind-autoloading-php-files-using-composer.html
You'll have to include/require the class anyway, otherwise PHP won't know about the namespace.
You don't necessary have to do it in the same file though. You can do it in a bootstrap file for example. (or use an autoloader, but that's not the topic actually)
The issue is most likely you will need to use an auto loader that will take the name of the class (break by '\' in this case) and map it to a directory structure.
You can check out this article on the autoloading functionality of PHP. There are many implementations of this type of functionality in frameworks already.
I've actually implemented one before. Here's a link.
I agree with Green, Symfony needs namespace, so why not use them ?
This is how an example controller class starts:
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class WelcomeController extends Controller { ... }
Can I use it to import classes?
You can't do it like that besides the examples above. You can also use the keyword use inside classes to import traits, like this:
trait Stuff {
private $baz = 'baz';
public function bar() {
return $this->baz;
}
}
class Cls {
use Stuff; // import traits like this
}
$foo = new Cls;
echo $foo->bar(); // spits out 'baz'
The use keyword is for aliasing in PHP and it does not import the classes. This really helps
1) When you have classes with same name in different namespaces
2) Avoid using really long class name over and over again.
Using the keyword "use" is for shortening namespace literals. You can use both with aliasing and without it. Without aliasing you must use last part of full namespace.
<?php
use foo\bar\lastPart;
$obj=new lastPart\AnyClass(); //If there's not the line above, a fatal error will be encountered.
?>
Namespace is use to define the path to a specific file containing a class e.g.
namespace album/className;
class className{
//enter class properties and methods here
}
You can then include this specific class into another php file by using the keyword "use" like this:
use album/className;
class album extends classname {
//enter class properties and methods
}
NOTE: Do not use the path to the file containing the class to be implements, extends of use to instantiate an object but only use the namespace.

Is this a good way to use Namespaces in PHP

I have studied the use of Namespaces in PHP a while back but recently looking at a project that used the use keyword and then accessed the namespaced object as if they were normal without namespace.
My question is, is the code below correct, it hs a file index.php and uses the namespace MyLibrary\Base it then uses use to bring in \MyLibrary\Registry \MyLibrary\User and \MyLibrary\Request
It then can access any of these object without putting there namespace in front of them, so the actual code below the use section looks like a normal pre-namespace php file.
I am asking if this is how you use namespaces? Or am I missing something?
File: index.php
<?php
namespace MyLibrary\Base;
use \MyLibrary\Registry;
use \MyLibrary\User;
use \MyLibrary\Request;
class Base
{
public $registry;
function __construct($registry)
{
$this->registry = $registry;
$this->user = New User;
$this->request = new Request;
# code...
}
}
?>
File: registry.class.php
<?php
namespace MyLibrary\Registry;
class Registry
{
public $user;
function __construct($user)
{
$this->user = $user;
# code...
}
}
?>
Yes. The use-statement imports the class- or namespace-name into the current scope. To write everything that short is the reason, why the PHP-devs implemented namespaces ;)
namespace MyFirstNamespace {
class Foo {}
}
namespace MySecondNamespace {
use \MyFirstNamespace\Foo as Bar;
$foo = new Bar;
}
a) it make everything more readable, because its much shorter, than Vendor_Package_Foo_Bar_XyzClass and b) you can exchange the classes to use very fast.
# use \MyFirstNamespace\Foo as Bar; // I don't like Foo anymore
use \MyFirstNamespace\SimilarToFoo as Bar;
Namespacing has a lot of advantages to it.
The first on is you can reuse method names and even class names if it makes sense provided they exist within a different namespace. Example:
namespace \myNamespace\data\postgres;
class DataBase extends \PDO
{
}
namespace \myNamespace\data\mysql;
class DataBase extends \PDO
{
}
You could even reuse names that are normally reserved for PHP functions
namespace \myNamespace\dir;
function makedir ()
{
if (// some condition is true)
{
\makedir ();
}
}
All of this is intended to make it easier to use code from different sources together without having to worry about naming conflicts. Provided programmers are courteous enough to observe a few simple rules then the chances of name conflicts are hugely reduced. Actually, pretty much the only rule you need to concern yourself with to avoid naming conflicts is to make the first level of your namespace your own. For example, use your company name, or some other way of identifying you as a unique vendor as the first level of your namespace and everything should be good.
For example I use \gordian as the root namespace in all the code I write, as I can then call my classes under that namespace anything I like without worrying about them colliding with someone who chose a different root namespace.
So what's wrong with PEAR conventions, you might ask? A lot of projects follow them, including the popular Zend framework.
The answer is names become very unwieldy very quickly. For instance, Zend, as it follows the PEAR convention, uses a sort of pseudo-namespacing. All the classes in the collection start with Zend_ and with each level of class hierachy add a further part to the name.
Ze
As a result, you end up with class names like Zend_Db_Adaptor_Abstract and Zend_Dojo_Form_Decorator_TabContainer.
Should Zend update their framework to use namespaces (which I'm told is happening with Zend Framework 2.0) then they'd be replaced with \Zend\Db\Adaptor\Abstract and \Zend\Dojo\Form\Decorator\TabContainer instead. So what, you might ask? The answer is that you can alias them to much shorter names with the Use keyword, as you've already seen. This means you don't have to keep writing the full class name out, but only as far as to what you've aliased.
use \Zend\Dojo\Forn\Decorator as Dec;
$a = new Dec\TabContainer; // Not easy to do without namespaces!
Further more, if you're already in a given namespace, then you don't even have to use the use keyword to access other items within the same namespace by a short name, as it happens automatically for you in that case. For framework writers this is a huge timesaver.
For example, you might see something like the followign in Zend Framework 2 (as I'm not working on it in any way, this is purely an example and not from the actual ZF2 source).
namespace \Zend\Db\Adaptor;
class Postgres extends Abstract // We don't need to use \Zend\Db\Adaptor\Abstract here because it's in the same namespace already anyway
{
}
There are other benefits too, such as it makes autoloaders ridiculously simple to make (provided your namespace structure maps exactly onto your filesystem directory structure).
Namespaces can seem like one of those features that aren't really very important, or don't even seem to make any sense, but after using them for a little while their usefulness will suddenly become very obvious.

Is it bad to include all the Namespaces and access Classes with just their class name in PHP?

Recently I have started to play around with Namespaces in PHP, I am not a fan of the chosen Namespace separator / (as most others have a mutual feeling) /
Below I have a very basic/simple example of using Namespace in PHP.
I have a Registry.class.php file that has a Registry class that is in the Namespace Library
I also have the file Controller.class.php below that has a Controller class that is in the Namespace called Project
Now in this Project Namespace I need access to the Registry object that is in a different Namespace, Library So I use use Library\Registry to Import that Namespace
With that done, I am able to simply access my Registry class like this...
$this->registry = new Registry;
Now if I had not used use Library\Registry then I would have to access it like this
$this->registry = new /Library/Registry;
So this is where my question begins.
For this simple example I am just bringing in the Registry class, in a real project, imagine several other classes and namespaces being brought in, So I would be using
use Library\Registry and use Library\SOME OTHER CLASS and use Library\YET ANOTHER CLASS etc...
I can then operate on the Objects/classes as if they were in this namespace to begin with so instead of pre-fixing the class name with its appropriate Namespace name, I simply just instantiate the class by its name ( new Registry;) instead of new /Library/Registry;
I would like to know if this is considered bad practice or not? It greatly simplify's things and makes the code look cleaner IMO, but if there is anything bad about this method I would like to know before I write a lot of code using this method. Should I be pre-fixing my classes when I instantiate them with their namespace INSTEAD of importing them with the use /Path/to/Namespace/Classname ?
Please share your knowledge with me, I realize it will work either way but I want to make sure. Example classes and namespaces are added below:
Controller.class.php
<?php
namespace Project
{
use Library\Registry;
class Controller
{
public $registry;
function __construct()
{
include('E:\Library\Registry.class.php');
$this->registry = new Registry;
}
function show()
{
$this->registry;
echo '<br>Registry was ran inside testcontroller.php<br>';
}
}
}
?>
Registry.class.php
<?php
// Registry.class.php
namespace Library
{
class Registry
{
function __construct()
{
echo 'Registry.class.php Constructor was ran';
}
}
}
?>
One of the primary purposes of namespaces is to prevent name conflicts in large code bases and across shared code and imported libraries. If you're not having name conflict issues, then I don't necessarily see anything wrong with using each class. If you find yourself doing this for all your classes, however, then I would question why you're using namespaces in the first place. This would only seem to make sense to me if your code was going to be used as an API or library by someone else.

Categories