Disable namespace usage is certain classes/files - php

I'm working on a plugin system for my CMS, inside my CMS I use namespaces a lot.
What I would like to have is that the developers of the plugins don't have to use namespaces inside their plugin, because they can be very complicated for developers who doesn't have used namespaces before. The main problem with the namespaces is the events which can be registered. Right now, plugin developers have to load an Event class using use \events\Event;, and if they just import the class they are still not able to use new Event(); because it uses namespaces. What I would like to have is that they can just use new Event(); (The class itself would be autoloaded by the CMS's auto loader, so no include required).
So basically, I would like to have namespaces disabled in certain classes or files. So new \events\Event(); will just look like new Event(); without removing the namespace events; from the Event class.
I hope I explained it clear, I'm not the best in explaining this kind of stuff.

No. In other words, this won't work:
namespace Foo {
class Event {}
include('plugin.php'); // plugin.php cannot just do new Event();
}
That shouldn't be a problem really, since your CMS's plugin development documentation should be clear about the namespace usage and plugin developers would simply need to write something like
use Plugin\Namespace\Events\MyEventType;
to refer to MyEventType without needing to qualify it. Surely that's not too much to ask of plugin authors?

I'm not sure if I understand completely, but to run code in "global" namespace, you can do this:
namespace {
// this runs in global namespace
}
See also: Defining multiple namespaces in the same file

AFAIK it is not possible, but if you use a loader that includes the needed files so that a plugin author could include a class with loader::load('someclass'); you can let the loader return the full classname with namespace and the plugin could use it:
$em_classname = Loader::load('eventmanager');
//dymamic use
$em = new $em_classname;
$em->registerEvent();
//static use
$em_classname::registerEvent();
For dynamic use you could even return an instance of the class instead of the class name.

Related

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.

PHP PSR-0 Static Class

I'm trying to rewrite an OO PHP site (that loosely follows an MVC structure) so it uses namespaces - and want to follow PSR-0.
In the current site I have a class (called APP) which is full of static methods that I call all over the place to handle things such as getting config data eg; APP::get_config('key').
Obviously with namespacing, I would need to call \TheNameSpace\App::get_config('key'). I use this class frequently, so want to avoid having to prefix the namespace every time I use it. I do call methods in it from within other classes, which would usually be under a sub-namespace - so changing the namespace at the top of the file won't really work.
So, I guess my question is, what is the easiest way to have a 'global' class with methods that I can call anywhere without having to prefix with the namespace each time?
namespace Foo;
use Bar;
Then you do not have to do \Bar\fn
So in your case:
namspace Foo;
use TheNameSpace\App;
App::get_config('blah')
Read the section in the php manual on using/aliasing namespaces.
http://www.php.net/manual/en/language.namespaces.importing.php
You can exclude the namespace by using "use". You can name it whatever you want.
use TheNamespace\App as App //You can name it anything here
App:config('key');
At top of your scripts add
use TheNameSpace\App as MyApp
for example. You can then use it like
app = new MyApp();
in your scripts. Of course you needn't to use an alias here. Just
use TheNameSpace\App
app = new App();
will work, too.
A global class that's implementing this one is bad style and you shouldn't do it like this:
class MyApp extends TheNameSpace\App { }
....
myApp = new MyApp();

Automatically using facades in a package in laravel 4

I'm developing some packages a lot of which are based on code that was in the main app, or from examples that are based on writing the code in an app rather than a package. I keep forgetting to add a Use View; or Use Controller; in the various files and am having to manually check and add these to every single PHP script (that needs them) in the package.
Is there a way of automating this so that I only have to declare them once in a package, or better still get them to pass through to the facades in the main app?
I'm afraid there isn't.
This is because your package code has its own namespace, and so does the Illuminate core.
PHP's use-statements are only on per-file basis.
When your scripts uses classes from another namespace, you have 2 options.
Adding use-statements (to the Facades) to alias the class to the current namespace
Referencing the full namespace of the facade (starting from the global namespace ), either the alias in the global namespace which Laravel automatically creates (\View), or the original full namespace of the facade (\Illuminate\Support\Facades\View)
Example of referencing the full namespace:
<?php
namespace My\Package;
class SomeClass
{
public function doSomething()
{
// reference full namespace
$view = \Illuminate\Support\Facades\View::make('someview');
// or
$view = \View::make
}
}
?>
This might seem as a way to not have to use use-statements, but in my opinion it's worse. So I recommend u to just get used to adding these use-statements.
You should see it as a best practice: these use-statements clearly state the dependencies of your class (or file). It's always better to try and lower the amount of these.

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.

Why does Codeigniter assume I want to create an instance of the class when using $this->load?

In Codeigniter, when we use $this->load('class_name') in the controller, CI will try to create an instance of the class/model using its constructor.
But sometimes, I don't actually need an instance from that class, I just want to call some static functions from it. Also, there is a big limitation with $this->load('class_name'), it does not allow me to pass parameters to the constructor (unless we extend or modify the core class of CI).
I think the $this->load('class_name') function should only do a require_once on the class php file for me, and let me freely do things (create instance/call static functions) with the class in the controller.
Should I simply ignore this function and use require_once or writing my own __autoload function to load up the classes? This way, I just feel strange because it seems I am not writing codes inside the CI box.
You can pass parameters to your constructor. See the "Passing Parameters When Initializing Your Class" section in the user guide.
I found CodeIgniter's object creation and loading to be very limiting. I want full control over my code, and little magic in the background. I have instead started using Doctrine's Class Loader. It's very lightweight and is essentially SPL autoloading (also a good alternative). You don't need the whole Doctrine shebang with ORM and all that stuff, just the ClassLoader. There's some configuration tinkering to get this right, but it works wonders.
With PHP 5.3 I now have namespaced classes in the Application directory. For instance I created a new class in the Tests directory: Application\Tests\SomeTest.php
That test could look something like this:
namespace Tests;
class SomeTest {
...
}
I would use this class in my code (controllers, views, helpers) by simply using the fully qualified namespace (i.e. $test = new \Tests\SomeTest) or a "use" statement at the top of my code (use \Tests\SomeTest as SomeTest).
In this way I intend to replace all libraries and models with OO namespaced variants. There are many benefits to this: fast autoloading with SPL, full IDE intellisense support for classes/methods (CodeIgniter is really bad for that), your code is more portable to other frameworks or projects.
That said, I still use a lot of the CodeIgniter engine. This basically means I have $CI =& get_instance() in most of my classes. It's still a work in progress and I think the main reason I need CI is for it's database access. If I can factor that out ... and use something like Dependency Injection, then I won't need CodeIgniter in my classes at all. I will simply be using it for it's MVC framework, and using it's methods occasionally in my controllers.
I know this goes above and beyond your question, but hopefully it's some food for though - and it helps me to get it in writing too.

Categories