I've got a few PHP5.2- frameworks using long classnames like such:
class Product_Sub_SomeClass {
...
}
I'd like to be able to provide a way for PHP5.3+ users to use namespaces and short class names whilst retaining PHP5.2 compatibility of the framework.
The above example class should be available in PHP5.3 developers' code as:
use Product\Sub;
$someclass = new SomeClass();
But the exact same class (same sourcecode) should also be usable to PHP5.2 users as:
$someclass = new Product_Sub_SomeClass();
Can I just provide an additional file that handles all the aliasses or is there some other or better mechanism available?
What is best practice to provide namespaces and class aliasses to PHP5.3+ users of a PHP5.2- framework?
Found my own answer to this problem:
class Product_Sub_SomeClass {
...
}
// Alternative PHP 5.3+ namespace\class
if (function_exists('class_alias')) {
class_alias('Product_Sub_SomeClass', 'Product\Sub\SomeClass');
}
Related
I'm trying to integrate the Playfab PHP SDK into CakePHP 4.0.4,
but Cake doesn't like the following line (included in the SDK example):
$apiReflection = new ReflectionClass("PlayFab" . $PlayFabApi . "Api");
it outputs the following error:
Class 'App\Controller\ReflectionClass' not found
As far as I know ReflectionClass is native class in PHP, so I understand CakePHP is using some kind of PHP subset that doesn't allow ReflectionClass, probably because this class allows reverse engineering and so on.
Is there anything else I am missing?
and most important, how can I make new ReflectionClass() constructor work without compromising the whole project security?
As usual: if you want to instantiate a class from the global namespace, while your current code is in another namespace, you have to prefix the class name using a backslash. Try to use :
$apiReflection = new \ReflectionClass
After some more research I've found the solution was as simple as including:
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
I am assigned to work on maintaining an old PHP project. The PHP project uses Kohana framework. I installed Eclipse Oxygen for PHP developer and created a PHP project to include those PHP codes. But, I found that Eclipse Oxygen marks tons of errors due to unable to resolve the reference to our classes autoloaded by Kohana framework. Because, Kohana utilizes PHP's autoloading feature and change the class name. For example, we have a class called common_Core in common.php. Kohana autoloaded the class and change the class name to common.
In common.php:
class common_Core {
public static function myFunc1() {
. . .
}
}
In client.php, we just reference this class with name common.
$result = common::myFunc1();
Eclipse Oxygen will mark common as not resolved and suggest to change to common_Core. Other Eclipse versions (Mars, Neon) won't mark those as errors but can not use Ctrl-click to jump to that method either. Does anyone use Kohana framework's autoload feature to load your own class? How do you make Eclipse to resolve your class?
As mentioned earlier, this is an old project contains tons of PHP codes. So, changing all reference from common:: to common_Core:: probably is not a good solution.
P.S. I just have an idea to change the class name from common_Core to common and that seems to fix the Eclipse issue. But, that also have the risk of class name conflict with other libraries unless namespace is used. This old PHP project does not use namespace. Anyway, still want to know if there is a way for Eclipse to work with PHP project using Kohana framework.
It sounds like you have strange autoloading, especially if you have file named common.php that has a class named common_Core in it. Can you not make a newer standard in your new scripts with namespaces? I imagine your autoloader can handle this standard.
/vendor/Common/Core.php
namespace Common;
class Core
{
public static myFunc()
{
}
}
client.php
# Reassign the class to "common" if need be
use \Core\Common as common;
# Assign
$result = common::myFunc();
Or perhaps just using the use might work?
# Reassign the class to "common" if need be
use \common_Core as common;
# Assign
$result = common::myFunc();
Also, if you see their manual here, it says:
When calling a class that has not been loaded (eg: Session_Cookie), Kohana will search the filesystem using Kohana::find_file for a file named classes/session/cookie.php.
If your classes do not follow this convention, they cannot be autoloaded by Kohana. You will have to manually included your files, or add your own autoload function.
It seems that Kohana framework creates alias class names using eval() in runtime for autoloaded classes with certain postfix (e.g. common_Core -> common, email_Core -> email). Not sure why alias names are needed. That practice not only increase risk of name conflicts (some old PHP code don't use namespace), it confuses Eclipse and Eclipse marks those alias names as errors. With eval(), there is no way Eclipse (or any PHP IDE) can verify that alias class name because it is determined in runtime. An easy solution is to drop the postfix. For example, rename the class common_Core to common. Then, you can still use Kohana framework without the side effect.
Kohana.php:
. . .
. . .
if ($filename = self::find_file($type, self::$configuration['core']['extension_prefix'].$class))
{
// Load the class extension
require $filename;
}
elseif ($suffix !== 'Core' AND class_exists($class.'_Core', FALSE))
{
// Class extension to be evaluated
$extension = 'class '.$class.' extends '.$class.'_Core { }';
// Start class analysis
$core = new ReflectionClass($class.'_Core');
if ($core->isAbstract())
{
// Make the extension abstract
$extension = 'abstract '.$extension;
}
// Transparent class extensions are handled using eval. This is
// a disgusting hack, but it gets the job done.
eval($extension);
}
. . .
. . .
P.S. After reading Kohana framework in detail, I found the eval() is used to implement the so called Transparent Class Extending feature. Please see the two links below:
Transparent Class Extending: https://v2docs.kohanaframework.org/3.3/guide/kohana/extension
Cascading FileSystem: https://v2docs.kohanaframework.org/3.3/guide/kohana/files
I found it is wrong use of Kohana framework in our old code. We should not declare any class with _Core postfix as they are reserved for Kohana core classes for extending. Since there is no common_Core Kohana class, we should just name it as common. However, there is email_Core Kohana class, we should declare a class email to extend from email_Core.
in application directory:
class common {
// there is no common_Core in Kohana
}
class email extends email_Core {
// there is email_Core in Kohana
}
Anyway, I still think using eval() is bad practice and dangerous. That make Kohana framework not compatible with any other PHP IDE if you use the transparent class extension incorrectly.
Found other similar posting discussing the same issue:
http://forum.kohanaframework.org/discussion/212/can-developers-remove-evalclass-class-extends-class-_core-/p1
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.
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.
Just a quick question on your preference of using PHP namespaces or class prefixing.
<?php
// ----- namespace -----
use My\Namespace;
$object = new Namespace\Object;
// ----- prefix with PR -----
$object = new PF_Object; //or
$object = new PFObject;
Which do developers prefer? I know why the use of namespaces can bring great advantage to applications, but also can quite a hindrance in PHP in my own opinion.
Thanks!
Combine use with an alias:
use My\Namespace\Foo as Foo;
$object = new Foo;
It's also useful like so:
namespace My\Debug\Stuff;
use My\Production\Stuff\Foo as BaseFoo;
class Foo extends BaseFoo {}
Why would you consider namespaces a hindrance?
class prefixing seemed to me like a sort of a hack to implement 'in code' a mecanism to implement namespaces.
Newer code now has the option to use a native built-in way of handling namespaces. This is a much cleaner approach, in my very humble opinion.
Consider this popular yet eye-opening example that allows legacy code to use namespace:
// Using native namespace features to shorten class prefixes
<?php
use Sabre_DAV_Auth_Backend_PDO as AuthBackend;
use Zend_Controller_Action_Helper_AutoComplete_Abstract as AutoComplete;
$backend = new AuthBackend();
?>
Clearly, there's no need to use the underscore character to fake namespaces any more, so I suppose the question boils down to "is it a good idea to use underscore characters in class names".
IMO, the answer is no, firstly because it looks ugly (IMO) and secondly because some older class loaders could get confused by a class name that includes an underscore.
well
if you are running PHP 5.2.X you only have the option 2
but if you are running PHP 5.3.Xyou could use both.
In my case running PHP 5.3.X I would use the feature that the new version of the language offers. To make an analogy is likely be running JAVA 1.6 and don't use generics (or sort of)