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.
Related
Why only static call return 2?
it seems to me that a class call not by absolute name should depend on the current namespace in the class
<?php
namespace A {
class B {
static function test(){
echo 1;
}
static function check(){
B::test();//1 why?
self::test();//1
static::test();//2
}
}
}
namespace B {
class B extends \A\B {
static function test(){
echo 2;
}
}
}
namespace {
B\B::check();
}
B::test() is executed inside the A namespace and therefore takes the B class, that is provided by the A namespace. Therefore A\B::test is called. The context of the current class is not relevant for that.
The following example shows, that the heredity is irrelevant for this behavior.
<?php
namespace A {
class B {
static function test() {
echo 3;
}
}
class A {
static function test(){
echo 1;
}
static function check(){
B::test();//3
self::test();//1
static::test();//2
}
}
}
namespace B {
class B extends \A\A {
static function test(){
echo 2;
}
}
}
namespace {
B\B::check();
}
static::test returns 2 eventhough you are in the A namespace, because static takes the context from the calling super class and not the current namespace.
self::test returns 1, because self takes the context of the current class instead of the super class.
In PHP, how do I find out if a class method was called via a method inherited from a trait?
Say I have a class myClass that uses the Psr\Log\LoggerTrait (see: PSR-3). I need to be able to find out if the method myClass::log() was called via a method from the Psr\Log\LoggerTrait, for example LoggerTrait::debug(), or if it was called directly from outside myClass.
All the methods are non-static.
This is related to a debugging package. I'm not trying to alter behavior based on the caller, I just need to be able to pass that information forward. And to be more precise, I need just the entry point, ie. just the last call outside of my package.
I'm looking at debug_backtrace() but it doesn't seem to offer any direct solutions. Is there some rational way of doing this?
Here's some code:
<?php
class myClass
{
use Psr\Log\LoggerTrait;
public function log($level, $message, array $context = array())
{
if (called_via_trait) {
...
} else {
...
}
}
}
$myObject = new myClass;
$myObject->log('debug', 'This is a direct call');
$myObject->debug('This is a call via a trait method');
You could use get_called_class to determine the class that called it.
trait Test {
public function doTest() {
echo get_called_class() . "\n";
}
}
class Some {
use Test;
public function myFunc() {
$this->doTest();
}
}
$some = new Some();
$some->myFunc(); // Outputs "Some" since Some uses Test
So in your case, inside your class, you could do something like
function test() {
if(get_called_class() == 'myClass') {
// You're in the myClass class
} else {
// You're not in the myClass class
}
}
Yes, you have to use debug_backtrace(); Please follow my example:
namespace Psr\Log;
class LoggerTrait{
public static function debug(){
return myClass::log();
}
}
class myClass{
public static function log(){
$trace = debug_backtrace();
if(isset($trace[1])){
echo'<br />Called by <b>'.$trace[1]['class'].'</b>. ';
} else {
echo'<br />Called by <b>'.$trace[0]['class'].'</b>. ';
}
if(isset($trace[1]['class']) && $trace[1]['class']!=get_class()){
echo'Called outside';
} else {
echo'Called inside';
}
//return get_class();
}
}
trait ExampleTrait {
public function doSay() {
echo LoggerTrait::debug();
echo myClass::log();
}
}
echo LoggerTrait::debug();
echo myClass::log();
echo ExampleTrait::doSay();
I have two classes:
class Init {
public function test() {
echo 1;
}
public static function loadSecond() {
// Load the class
}
}
class Second extends Init {
public function test2() {
echo 2;
}
}
I need to load Second class only by request. For example:
$init = new Init();
$init->test();
$second = $init::loadSecond();
$second->test2();
Replace // Load the class with
return new Second()
You just need to create a new object. (I do not know why you need it to be that way, but this should work for your purpose.
I'm not sure what you need to do.
If you mean to include a class whenever you need it automatically :
As Marcin Orlowski mentionned it, what you need is to use the autoloading function of PHP.
Basically it should look like :
function __autoload ($name)
{
include "/path/to/my/includes/" . $name . "inc.php";
}
If you mean creating an object from another class, you should probably do like
class Init {
public function test() {
echo 1;
}
public static function loadSecond() {
return new Second;
}
}
class Second extends Init {
public function test2() {
echo 2;
}
}
What you need is class autoloading feature implemented. It's basically supported by PHP, so follow the docs: http://php.net/manual/pl/language.oop5.autoload.php
Whats wrong with me OOP here.
I want to inherit from Class A
The return_output method will do something common so I don't want to write that in the inherited classes.
However when I do B->return_output() I want it to run the do_something method in Class B, but I see that it always runs the method from Class A.
Should I replace $this with something else?
class A {
private function do_something() {
// do something
}
public function return_output() {
$op = $this->do_something();
// add some wrappers to $op
return $op;
}
}
class B extends A {
private function do_something() {
// do something different
}
}
var newClass = new B;
echo B->return_output();
use protected and not private since you are running it inside of scope a and scope b can't access private scope a:
class A {
protected function do_something() {
echo('ado_something');
}
public function return_output() {
$op = $this->do_something();
// add some wrappers to $op
return $op;
}
}
class B extends A {
protected function do_something() {
echo('bdo_something');
}
}
$newClass = new B;
echo $newClass->return_output();
Whilst developing an object-orientated HMVC that has a super-object, at some point during the application process, it required the utilisation of namespaces. Here, namespaces will act as a method of "versioning" different code that can be accessed the same way. In the scaled down example below, I am able to execute the class Foo with the method qux if I am in version A or B. I understand that if I utilise self:: rather than $this the problem will disappear, however, I wish to avoid this. At the moment, I get the following PHP error:
Fatal error: Using $this when not in object context
So my question is, how can I use $this in this particular context?
namespace
{
$gamma = new \Gamma();
$gamma->execute('A', 'Foo', 'qux');
// ...
class Alpha
{
// ...
}
class Beta extends Alpha
{
public function foo($input)
{
echo $this->bar($input);
}
public function bar($input)
{
return $input;
}
}
class Gamma extends Beta
{
public function execute($space, $class, $method)
{
call_user_func_array(array($space . '\\' . $class, $method), array());
}
}
}
namespace A
{
class Foo extends \Gamma
{
public function qux()
{
$this->foo('I like turtles');
}
}
}
namespace B
{
class Foo extends \Gamma
{
public function qux()
{
$this->foo('I like strawberries');
}
}
}
The expected output is:
"I like turtles"
Any advice, answers, guidance are much appreciated. :3
Solved.
I was passing the class via the call_user_func_array function statically. Therefore, I was unable to use $this. Thus, an initiation of the requested class would be required, and passed through as a variable, like so:
// ... Continuing from Beta::execute() ...
$class = $space . '\\' . $class;
$class = new $class();
call_user_func_array(array($class, $method), array());
This is what abstract methods are for.
You should declare Master as an abstract class, and qux as an abstract method:
abstract class Master
{
public function __construct()
{
$this->qux();
}
abstract public function qux();
}
class Foo extends Master
{
public function qux()
{
....
}
}