I used to have several library classes with the exact same methods. Figured I'd learn a bit more about two important aspects of coding; Traits and DRY.
I have the following trait:
<?php
namespace App\Berry;
trait Lib
{
public function getIDs()
{
$oClass = new \ReflectionClass(get_called_class());
$aConstants = $oClass->getConstants();
foreach($aConstants as $sKey => $mValue)
{
if(!is_int($mValue))
{
unset($aConstants[$sKey]);
}
}
return array_values($aConstants);
}
}
The following class:
namespace App\Berry;
use Lib;
class postType
{
const POST_TYPE_BLOG_ID = 1;
const POST_TYPE_BLOG_LABEL = __('blog', 'lib');
const POST_TYPE_PAGE_ID = 2;
const POST_TYPE_PAGE_LABEL = __('page', 'lib');
const POST_TYPE_NEWS_ID = 3;
const POST_TYPE_NEWS_LABEL = __('news', 'lib');
}
And am calling it like this in my PicturesController class:
$cPostTypesLibrary = new postType();
$this->set('aPostTypes', $cPostTypesLibrary->getIDs());
Now to me, this seems almost exactly like the tell me to do in the docs example #4 (About using multiple traits)
The only difference I have is I have the use outside of my class due to getting cannot use class because it is not a trait
What am I missing here?
Your class is not using the trait, you are instead using the other use of the use keyword and trying to import the Lib class from the same namespace into, well, the same namespace.
To use traits correctly, go back to the documentation, and look at where they are placed. The use statement is placed inside of the class definition. In your case, it would look like this:
namespace App\Berry;
class postType
{
use Lib;
// ...
}
You have to declare the trait inside the class
class postType
{
use Lib;
}
Related
I'm trying to run this code on the same file:
namespace Foo1\Bar\SubBar;
class SubBarClass {
public function __construct() {
echo 'From Foo1';
}
}
namespace Foo2\Bar\SubBar;
class SubBarClass {
public function __construct() {
echo 'From Foo2';
}
}
use Foo1\Bar\SubBar;
$foo1 = new SubBarClass;
use Foo2\Bar\SubBar;
$foo2 = new SubBarClass;
The ideia is to change namespaces and echo the related value.
But it's returning the following error:
( ! ) Fatal error: Cannot use Foo2\Bar\SubBar as SubBar because the name is already in use in C:\wamp\www\xxx\namespaces.php on line 30
Line 30: use Foo2\Bar\SubBar;
How can I interchange namespaces on the same file?
Thks!
use keyword is used to import that namespace to be accessed in your current file scope. It does not act as a namespace "instance constructor".
You're current under Foo2\Bar\SubBar namespace. Like a directory of classes, while you're here, you should access other namespaces from the root (\):
$foo2 = new SubBarClass;
$foo1 = new \Foo1\Bar\SubBar\SubBarClass;
There is no need to use use for those namespaces (although you can, specially when they share parent namespaces), they are already declared in the same file you're using them.
For more information about this, consider reading the manual, where it describes using multiple namespaces in the same file.
This happens because the last defined namespace is the one currently active.
So, when I type:
use Foo1\Bar\SubBar;
I'm still on the last defined namespace: Foo2\Bar\SubBar.
Hence, when I type:
use Foo2\Bar\SubBar;
I'm trying to use the currently active namespace. That's why the Fatal error is returned.
On possible solution is:
namespace Foo1\Bar\SubBar;
class SubBarClass {
public function __construct() {
echo 'From Foo1';
}
}
namespace Foo2\Bar\SubBar;
class SubBarClass {
public function __construct() {
echo 'From Foo2';
}
}
use Foo1\Bar\SubBar;
$foo1 = new SubBar\SubBarClass;
echo '<br>';
$foo2 = new SubBarClass;
Cheers!
If I have a PHP namespace as follows:
<?php
namespace A\B;
$test = new MyClass();
it seems every time I create a new instance of class, the name is prefixed with the namespace, e.g.
$test = new A\B\MyClass();
What happens if I don't want to use a namespace for another class, e.g. I want to call
$test = C\D\AnotherClass();
Currently this becomes:
$test = A\B\C\D\AnotherClass();
which results in an error.
For php7 you can wrap code in a namespace then call it with use in the global namespace declared using namespace with no name per the example below.
namespace FRED\WILMA\BAMBAM {
const FW = 2;
function fw() {
echo "<br>fw<br>";
}
}
namespace BARNEY\BETTY { // Create Namespace and add function
function bb() {
echo "<br>bb<br>";
}
}
namespace { // use global namespace
use FRED\WILMA\BAMBAM;
use BARNEY\BETTY;
BETTY\bb();
BAMBAM\fw();
}
I have code - working correct (I do not have to inculde class ReflectionClass):
class Test
{
const TYPE_ONE = "Number one";
const TYPE_TWO = "Number two";
static function getConstants() {
$oClass = new ReflectionClass(__CLASS__);
return $oClass->getConstants();
}
}
foreach (Test::getConstants() as $kay => $val):
echo "$kay -- $val <br/>";
endforeach;
But, when i try use ReflectionClass in code Yii2 i gets the message
PHP Fatal Error – yii\base\ErrorException
Class 'common\models\ReflectionClass' not found
If there are any Reflection classes in the framework or a way to declare ReflectionClass in Yii2
Because yii2 use namespaces, when you call new ReflectionClass() php looking for this class in the namespace that you declare at the beginnig of a file, in your case its namespace common\models; To load php's classes you need to prepend their names with \. So to instantiate ReflectionClass you need to write new \ReflectionClass(__CLASS__). More in documentation
How can I retrieve a class namespace automatically?
The magic var __NAMESPACE__ is unreliable since in subclasses it's not correctly defined.
Example:
class Foo\bar\A -> __NAMESPACE__ === Foo\bar
class Ping\pong\B extends Foo\bar\A -> __NAMESPACE__ === Foo\bar (it should be Ping\pong)
ps: I noticed the same wrong behavior using __CLASS__, but I solved using get_called_class()... is there something like get_called_class_namespace()? How can I implement such function?
UPDATE:
I think the solution is in my own question, since I realized get_called_class() returns the fully qualified class name and thus I can extract the namespace from it :D
...Anyway if there is a more effective approach let me know ;)
The namespace of class Foo\Bar\A is Foo\Bar, so the __NAMESPACE__ is working very well. What you are looking for is probably namespaced classname that you could easily get by joining echo __NAMESPACE__ . '\\' . __CLASS__;.
Consider next example:
namespace Foo\Bar\FooBar;
use Ping\Pong\HongKong;
class A extends HongKong\B {
function __construct() {
echo __NAMESPACE__;
}
}
new A;
Will print out Foo\Bar\FooBar which is very correct...
And even if you then do
namespace Ping\Pong\HongKong;
use Foo\Bar\FooBar;
class B extends FooBar\A {
function __construct() {
new A;
}
}
it will echo Foo\Bar\FooBar, which again is very correct...
EDIT: If you need to get the namespace of the nested class within the main that is nesting it, simply use:
namespace Ping\Pong\HongKong;
use Foo\Bar\FooBar;
class B extends FooBar\A {
function __construct() {
$a = new A;
echo $a_ns = substr(get_class($a), 0, strrpos(get_class($a), '\\'));
}
}
In PHP 5.5, ::class is available which makes things 10X easier. E.g.
A::class
Use Reflection class.
$class_name = get_class($this);
$reflection_class = new \ReflectionClass($class_name);
$namespace = $reflection_class->getNamespaceName();
I posted some questions previously regarding the use of Namespaces in PHP and from what I got, this example code I have below should be working.
However I am getting errors when I try to use Namespace in PHP like this. Here is the first error when running the code below as is...
Fatal error: Class 'Controller' not found in E:\Controllers\testing.php on line 6
E:\Controller\testing.php File
<?php
use \Controller;
include('testcontroller.php');
$controller = new Controller;
$controller->show();
?>
E:\Controller\testcontroller.php File
<?php
use \Library\Registry;
namespace Controller
{
class Controller
{
public $registry;
function __construct()
{
include('E:\Library\Registry.class.php');
$this->registry = new Registry;
}
function show()
{
echo $this->registry;
echo '<br>Registry was ran inside testcontroller.php<br>';
}
}
}
?>
E:\Library\Registry.class.php File
<?php
namespace Library\Registry
{
class Registry
{
function __construct()
{
return 'Registry.class.php Constructor was ran';
}
}
}
?>
As you can see I tried to make it as simple as possible just to get the Namespace part working. I have tried different variations and cannot seem to figure it out.
Even when using use statement, you need to specify the namespace of the class you are trying to instantiate. There are a lot of examples here: http://www.php.net/manual/en/language.namespaces.importing.php
To understand it better, I will describe to you how it works. In your case, when you do use \Controller, the whole Controller namespace becomes available to you, but not the classes that are in this namespace. So, for example:
<?php
include('testcontroller.php');
use \Controller;
// Desired class is in namespace!
$controller = new Controller\Controller();
// Error, because in current scope there is no such class
$controller = new Controller();
$controller->show();
?>
Another example:
testcontoller.php:
<?php
namespace Some\Path\To\Controller;
class Controller
{
function __construct()
{
}
function show()
{
echo '<br>Was run inside testcontroller.php<br>';
}
}
?>
testing.php:
<?php
include('testcontroller.php');
use \Some\Path\To\Controller;
// We now can access Controller using only Controller namespace,
// not Some\Path\To\Controller
$controller = new Controller\Controller();
// Error, because, again, in current scope there is no such class
$controller = new Controller();
$controller->show();
?>
If you wish to import exactly the Controller class, you need to do use Controller\Controller - then this class will be accessible in your current scope.
Its not that good idea to name the namespace, like the class, because it is confusing (and I think this is what happens here). There moment you define the alias via use Controller this referenes to either a class \Controller, or the namespace \Controller, but your class, because it is within the namespace, is named \Controller\Controller 1
use Controller;
$class = new Controller\Controller;
or
$class = new \Controller\Controller;
or
use Controller\Controller;
$class = new Controller;
The idea is, that the moment you try to access a class with its relative name it tries to map the "first part" against any alias defined using use (remeber use MyClass is the same as use MyClass as MyClass. The thing after as is the alias).
namespace MyNamespace\MyPackage\SomeComponent\And\So\On {
class MyClass {}
}
namespace Another {
use MyNamespace\MyPackage\SomeComponent; // as SomeComponent
$class = new SomeComponent\An\So\On\MyClass;
}
As you can see PHP finds SomeComponent as the first part and maps it against the SomeComponent-alias the line above.
You can read more about it in the manual about namespaces.
1 Its called "Full-qualified classname", if you name a class with its complete name.
When you put a class Controller in the namespace Controller, then you have to reference it that way:
$controller = new Controller\Controller();
\Controller would be a class in the global (default) namespace, i.e. as if you used no namespace at all.
Strangely I have found that in my example code from the Question above, if I change all the Namespace's that are defined to something like MyLibrary so it would be like this code below...
E:\Library\Registry.class.php File
<?php
namespace MyLibrary
{
class Registry
{
function __construct()
{
echo 'Registry.class.php Constructor was ran';
}
}
}
?>
Then when I use use MyLibrary\Registry; in another file, I am able to access it how I had planned...
$this->registry = new Registry;
The reason this is very strange to me is this now makes a class name appear to be a Namespace as well. So I would not need to set a Namespace to 'MyLibrary\Library' to access the Registry instead I would do it like I showed in this answer to be able to access it with just calling the name of the class.
I hope this makes sense and helps someone else. I will not accept this as the answer as I am hoping someone with more know-how will come in and post a better Answer with explanation
try
<?php
use \Library\Registry;
namespace Controller;
class Controller
{
public $registry;
function __construct()
{
include('E:\Library\Registry.class.php');
$this->registry = new Registry;
}
function show()
{
echo $this->registry;
echo '<br>Registry was ran inside testcontroller.php<br>';
}
}
?>
and
<?php
namespace Library\Registry;
class Registry
{
function __construct()
{
return 'Registry.class.php Constructor was ran';
}
}
?>
First off, I believe you are using composer or composer is initialised in your project. If so, check composer.json file for your autoload, psr-4 definition. For example, if the root of your application is "App", then in your psr-4, you should be doing "autoload": { "psr-4": { "App\\": "./" } },
Furthermore, remember to clear composer cache and dump-autoload from the terminal as follows:
composer clear-cache
composer dump-autoload