Retrieve the namespace of a class using a trait - php

Let's say I have a simple class like this that uses a trait.
<?php namespace A\B;
use C\FooTrait;
class D {
use FooTrait;
}
And my trait looks like this.
<?php namespace C;
class FooTrait {
public function getBaseNamespace()
{
// code
}
}
My expected behavior would be the following:
<?php
$d = new D;
// Shoud be 'A\B';
$d->getBaseNamespace();
But so far I haven't been able to do this using the reflection API. Any clues?

This might be a bit more simple than using reflection.
If you are trying to determine it from within the trait method.
You can use:
public function getBaseNamespace()
{
return preg_replace('/(.+)\\\\[^\\\\]+/', '$1', __CLASS__);
}

My final implementation is the following.
<?php namespace Tools\Namespaces;
use ReflectionClass;
trait NamespaceTrait {
public function getBaseNamespace()
{
$reflection = new ReflectionClass(__CLASS__);
return $reflection->getNamespaceName().'\\';
}
}

Related

Laravel/PHP Refactor code to use same different modal

I am using Laravel (PHP). I want to refactor below code to ask class A and class B to use the same funsth(). funSth() is repeated in two class while the only difference is the model.
Is there a way I can simplify to below? Is that possible to refactor it into second code?
Current:
class A {
public function funSth(){
Models\Profile::create();
}
public function main(){
$this->funA();
}
}
class B {
public function funSth(){
Models\Location::create();
}
public function main(){
$this->funB();
}
}
Expected:
class A {
public function main(){
(new Y)->funSth();
}
}
class B {
public function main(){
(new Y)->funSth();
}
}
class Y {
public function funSth(){
Models\AnyModel::create();
}
}
One way you could do this is to make a Trait. Traits essentially allow you to use the same code in multiple classes.
Base on the code in your question, your trait would look something like:
trait Y
{
public function funSth()
{
Models\AnyModel::create();
}
}
Don't forget to add the correct namespace for the file.
Then in your other classes you would have the use the use keyword inside the class body:
class A
{
use Y;
public function main()
{
$this->funA();
}
}
If you're trait is in a different namespace then you'll need to either give the full class name with the namespace or import the trait into your class.
After researching for a while. Here is my solution.
use Illuminate\Database\Eloquent\Model;
trait Y
{
protected function create(Model $model, array $attributes){
model->create($attributes);
}
}
Therefore, for Class A and Class B:
class A
{
use Y;
public function main($data){
$this->create((new Models\ModelAA), $data)
}
}
class B
{
use Y;
public function main($data){
$this->create((new Models\ModelBB), $data)
}
}
The basic idea is to use the abstract class Illuminate\Database\Eloquent\Model in trait Y and initialize model before it.

How to get parent namespace from Trait

I created a trait and i want to be able to get the namespace of the class using the trait. is this possible? self::class gives me the class name of the parent but not the entire namespace
You can use ReflectionClass->getNamespaceName() with the reflection of self::class.
MyTrait.php
namespace MyTraitNamespace;
Trait MyTrait{
public function echoClassNamespace()
{
$ref = new \ReflectionClass(self::class);
echo $ref->getNamespaceName(); //Will echo MyClassNamespace
}
public function echoTraitNamespace()
{
echo __NAMESPACE__; //Will echo MyTraitNamespace
}
}
MyClass.php
namespace MyClassNamespace;
use MyTraitNamespace\MyTrait;
class MyClass{
use MyTrait;
}

Why have multiple use statements in class

I'm curious about how use statements work in PHP. I was watching a tutorial and the code looked like this:
<?php
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ConversationTest extends TestCase {
use DatabaseTransactions;
}
Why does the DatabaseTransactions item have to be declared twice?
The use DatabaseTransactions; statement refers the use of Traits.
Traits are a mechanism for code reuse.
A example from the php.net manual:
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>

importing a global class from a namespace of the same name in php

Using namespace in this scenario is totally clear, I create a new namespace called ArrayObject and I use that class for my needs.
namespace NamespaceTesting;
class ArrayObject{
public $initVal;
function __construct($a){
$this->initVal = $a;
}
public function append($unusedVal){
var_dump($this);
}
}
$a = new ArrayObject("test");
$a->append("unusedVal");
the questioni is, if I want to use the global class of ArrayObject, I thought i should put use ArrayObject just before to use my code, but it doesn't work. what's wrong?
namespace NamespaceTesting;
class ArrayObject{
public $initVal;
function __construct($a){
$this->initVal = $a;
}
public function append($unusedVal){
var_dump($this);
}
}
// this is not working
use ArrayObject;
$a = new ArrayObject("test");
$a->append("unusedVal");
what am I interpreting wrongly? thank you
namespace NamespaceTesting;
class ArrayObject{
public $initVal;
function __construct($a){
$this->initVal = $a;
}
public function append($unusedVal){
var_dump($this);
}
}
// $a is an ArrayObject from global namespace, not from NamespaceTesting;
$a = new \ArrayObject();
$a->append("unusedVal");
var_dump($a);
You are creating the namespace NamespaceTesting and not ArrayObject And thus need to call it like so (Using namespaces)
use NamespaceTesting;
If you want to use the built in ArrayObject class.. you need to precede it with a slash
$a = new \ArrayObject("test");

How to detect the last namespace used in PHP?

If I had two classes in separate namespaces (and therefor files), and they both called a function in the global namespace - is there any way to indentify which namespace called that function short of passing the value?
namespace A;
class Test { function run() { \func(); }
...
namespace B;
class Test { function run() { \func(); }
...
function func()
{
// Did a class from "\A" call me or "\B"...?
}
My first thought was to use the __NAMESPACE__ constant. But that is computed in place so it would not solve this problem.
You could define versions of the function in each namespace that then calls func();
namespace A;
class Test { function run() { func(); }
...
namespace B;
class Test { function run() { func(); }
...
namespace A
{
function func()
{
\func(__NAMESPACE__);
}
}
namespace B
{
function func()
{
\func(__NAMESPACE__);
}
}
namespace
{
function func($namespace)
{
//work with $namespace
}
}
debug_backtrace() will show you the call stack. It also gives you the class name of the object that the calls were made from. You could parse this date out and find the namespace.
http://www.php.net/manual/en/function.debug-backtrace.php
function func()
{
$trace = debug_backtrace();
$class = $trace[1]['class']; //Should be the class from the previous function
$arr = explode($class, "\");
array_pop($arr);
$namespace = implode($arr, "\");
}
Let me know if that works. It will probably only work if func() is called from inside an object or class.

Categories