PHP __FILE__ inheritence - php

I am trying to write a method that I can use in extended classes that uses the file's full path. However, when I use __FILE__ I only get back the path for the class the inherited method is defined in. Here is an example:
foo.php
class foo
{
public function getFullFile()
{
return __FILE__;
}
}
bar.php
class bar extends foo
{
public function getFile()
{
return __FILE__;
}
}
example.php
$foo = new foo();
echo $foo->getFullFile() . PHP_EOL;
$bar = new bar();
echo $bar->getFullFile() . PHP_EOL;
echo $bar->getFile() . PHP_EOL;
The output of running example.php:
/my/full/path/foo.php
/my/full/path/foo.php
/my/full/path/bar.php
Is this expected behavior? Is there a better way to accomplish this? Am I doing something insanely stupid?

You can not refer to __FILE__ (for said reasons), but you can refer to the file the current object's class has been defined in:
class foo
{
public function getFullFile()
{
$c = new ReflectionClass($this);
return $c->getFileName();
}
}

__FILE__ is always the file where the constant is referred to. It's for debugging purposes to you can easily refer back to the exact file where the code that uses __FILE__ is located. It would be useless to say that it was in 'bar.php', when the definition resides in 'foo.php'.

Some code says more than thousand words...
B.php
<?
class B {
public function bar() {
return __FILE__;
}
}
A.php
<?
require "B.php";
class A extends B {
public function foo() {
echo parent::bar();
}
}
$a = new A();
$a->foo();
joe#joe-desktop:~$ php A.php
/home/joe/B.php

See http://php.net/manual/en/language.constants.predefined.php for more information on these 'magical constants'. If I am not mistaken these magical constants are a sort of macros and are determined at compile time, not runtime.

This is the expected behaviour __FILE__ will always evaluate to the filename of file in which interpreter finds it. Same with other magic constants (__METHOD__, __CLASS__, __LINE__ etc)
As far as I can tell, it is impossible to do waht you're trying to do.

I think if you want $bar->getFullFile() to return bar.php, you'll have to add the function to bar.php.
public function getFullFile() {
return parent::getFullFile();
}

Just use debug_backtrace() PHP function. Example of use (my library function my_die is placed in some included php file, but reports the callers location!):
function my_die($msg)
{
$bt = debug_backtrace();
$file = $bt[0]["file"];
$line = $bt[0]["line"];
$func = $bt[1]["function"];
# session info also!!!
$user = $_SESSION['user'];
error_log('Died in ' . $file . ': ' . $line . ': function ' . $func .
"(): user='{$user}': ip='{$_SERVER['REMOTE_ADDR']}': " . $msg .
" (browser: '{$_SERVER['HTTP_USER_AGENT']})'");
die($msg);
}

Related

bind a callback to the beginning and end of a method [duplicate]

Class test{
function test1()
{
echo 'inside test1';
}
function test2()
{
echo 'test2';
}
function test3()
{
echo 'test3';
}
}
$obj = new test;
$obj->test2();//prints test2
$obj->test3();//prints test3
Now my question is,
How can i call another function before any called function execution?
In above case, how can i auto call 'test1' function for every another function call,
so that i can get the output as,
test1
test2
test1
test3
currently i am getting output as
test2
test3
I cannot call 'test1' function in
every function definition as there may
be many functions. I need a way to
auto call a function before calling
any function of a class.
Any alternative way would also be do.
Your best bet is the magic method __call, see below for example:
<?php
class test {
function __construct(){}
private function test1(){
echo "In test1", PHP_EOL;
}
private function test2(){
echo "test2", PHP_EOL;
}
protected function test3(){
return "test3" . PHP_EOL;
}
public function __call($method,$arguments) {
if(method_exists($this, $method)) {
$this->test1();
return call_user_func_array(array($this,$method),$arguments);
}
}
}
$a = new test;
$a->test2();
echo $a->test3();
/*
* Output:
* In test1
* test2
* In test1
* test3
*/
Please notice that test2 and test3 are not visible in the context where they are called due to protected and private. If the methods are public the above example will fail.
test1 does not have to be declared private.
ideone.com example can be found here
Updated: Add link to ideone, add example with return value.
All previous attempts are basically flawed because of http://ocramius.github.io/presentations/proxy-pattern-in-php/#/71
Here's the simple example, taken from my slides:
class BankAccount { /* ... */ }
And here's our "poor" interceptor logic:
class PoorProxy {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($method, $args) {
return call_user_func_array(
$this->wrapped,
$args
);
}
}
Now if we have the following method to be called:
function pay(BankAccount $account) { /* ... */ }
Then this won't work:
$account = new PoorProxy(new BankAccount());
pay($account); // KABOOM!
This applies to all solutions that suggest implementing a "proxy".
Solutions suggesting explicit usage of other methods that then call your internal API are flawed, because they force you to change your public API to change an internal behavior, and they reduce type safety.
The solution provided by Kristoffer doesn't account for public methods, which is also a problem, as you can't rewrite your API to make it all private or protected.
Here is a solution that does solve this problem partially:
class BankAccountProxy extends BankAccount {
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function doThings() { // inherited public method
$this->doOtherThingsOnMethodCall();
return $this->wrapped->doThings();
}
private function doOtherThingsOnMethodCall() { /**/ }
}
Here is how you use it:
$account = new BankAccountProxy(new BankAccount());
pay($account); // WORKS!
This is a type-safe, clean solution, but it involves a lot of coding, so please take it only as an example.
Writing this boilerplate code is NOT fun, so you may want to use different approaches.
To give you an idea of how complicated this category of problems is, I can just tell you that I wrote an entire library to solve them, and some smarter, wiser, older people even went and invented an entirely different paradigm, called "Aspect Oriented Programming" (AOP).
Therefore I suggest you to look into these 3 solutions that I think may be able to solve your problem in a much cleaner way:
Use ProxyManager's "access interceptor", which is basically a proxy type that allows you to run a closure when other methods are called (example). Here is an example on how to proxy ALL calls to an $object's public API:
use ProxyManager\Factory\AccessInterceptorValueHolderFactory;
function build_wrapper($object, callable $callOnMethod) {
return (new AccessInterceptorValueHolderFactory)
->createProxy(
$object,
array_map(
function () use ($callOnMethod) {
return $callOnMethod;
},
(new ReflectionClass($object))
->getMethods(ReflectionMethod::IS_PUBLIC)
)
);
}
then just use build_wrapper as you like.
Use GO-AOP-PHP, which is an actual AOP library, completely written in PHP, but will apply this sort of logic to ALL instances of classes for which you define point cuts. This may or may not be what you want, and if your $callOnMethod should be applied only for particular instances, then AOP is not what you are looking for.
Use the PHP AOP Extension, which I don't believe to be a good solution, mainly because GO-AOP-PHP solves this problem in a more elegant/debuggable way, and because extensions in PHP are inherently a mess (that is to be attributed to PHP internals, not to the extension developers).
Additionally, by using an extension, you are making your application as un-portable as possible (try convincing a sysadmin to install a compiled version of PHP, if you dare), and you can't use your app on cool new engines such as HHVM.
Maybe it is a little bit outdated but here come my 2 cents...
I don't think that giving access to private methods via __call() is a good idea. If you have a method that you really don't want to be called outside of your object you have no way to avoid it happening.
I think that one more elegant solution should be creating some kind of universal proxy/decorator and using __call() inside it. Let me show how:
class Proxy
{
private $proxifiedClass;
function __construct($proxifiedClass)
{
$this->proxifiedClass = $proxifiedClass;
}
public function __call($methodName, $arguments)
{
if (is_callable(
array($this->proxifiedClass, $methodName)))
{
doSomethingBeforeCall();
call_user_func(array($this->proxifiedClass, $methodName), $arguments);
doSomethingAfterCall();
}
else
{
$class = get_class($this->proxifiedClass);
throw new \BadMethodCallException("No callable method $methodName at $class class");
}
}
private function doSomethingBeforeCall()
{
echo 'Before call';
//code here
}
private function doSomethingAfterCall()
{
echo 'After call';
//code here
}
}
Now a simply test class:
class Test
{
public function methodOne()
{
echo 'Method one';
}
public function methodTwo()
{
echo 'Method two';
}
private function methodThree()
{
echo 'Method three';
}
}
And all you need to do now is:
$obj = new Proxy(new Test());
$obj->methodOne();
$obj->methodTwo();
$obj->methodThree(); // This will fail, methodThree is private
Advantages:
1)You just need one proxy class and it will work with all your objects.
2)You won't disrespect accessibility rules.
3)You don't need to change the proxified objects.
Disadvantage: You will lose the inferface/contract after wrapping the original object. If you use Type hinting with frequence maybe it is a problem.
Perhaps the best way so far is to create your own method caller and wrap around whatever you need before and after the method:
class MyClass {
public function callMethod()
{
$args = func_get_args();
if (count($args) == 0) {
echo __FUNCTION__ . ': No method specified!' . PHP_EOL . PHP_EOL;;
} else {
$method = array_shift($args); // first argument is the method name and we won't need to pass it further
if (method_exists($this, $method)) {
echo __FUNCTION__ . ': I will execute this line and then call ' . __CLASS__ . '->' . $method . '()' . PHP_EOL;
call_user_func_array([$this, $method], $args);
echo __FUNCTION__ . ": I'm done with " . __CLASS__ . '->' . $method . '() and now I execute this line ' . PHP_EOL . PHP_EOL;
} else
echo __FUNCTION__ . ': Method ' . __CLASS__ . '->' . $method . '() does not exist' . PHP_EOL . PHP_EOL;
}
}
public function functionAA()
{
echo __FUNCTION__ . ": I've been called" . PHP_EOL;
}
public function functionBB($a, $b, $c)
{
echo __FUNCTION__ . ": I've been called with these arguments (" . $a . ', ' . $b . ', ' . $c . ')' . PHP_EOL;
}
}
$myClass = new MyClass();
$myClass->callMethod('functionAA');
$myClass->callMethod('functionBB', 1, 2, 3);
$myClass->callMethod('functionCC');
$myClass->callMethod();
And here's the output:
callMethod: I will execute this line and then call MyClass->functionAA()
functionAA: I've been called
callMethod: I'm done with MyClass->functionAA() and now I execute this line
callMethod: I will execute this line and then call MyClass->functionBB()
functionBB: I've been called with these arguments (1, 2, 3)
callMethod: I'm done with MyClass->functionBB() and now I execute this line
callMethod: Method MyClass->functionCC() does not exist
callMethod: No method specified!
You can even go further and create a whitelist of methods but I leave it like this for the sake of a more simple example.
You will no longer be forced to make the methods private and use them via __call().
I'm assuming that there might be situations where you will want to call the methods without the wrapper or you would like your IDE to still autocomplete the methods which will most probably not happen if you declare the methods as private.
<?php
class test
{
public function __call($name, $arguments)
{
$this->test1(); // Call from here
return call_user_func_array(array($this, $name), $arguments);
}
// methods here...
}
?>
Try adding this method overriding in the class...
If you are really, really brave, you can make it with runkit extension. (http://www.php.net/manual/en/book.runkit.php). You can play with runkit_method_redefine (you can need Reflection also to retrieve method definition) or maybe combination runkit_method_rename (old function) / runkit_method_add (new function which wraps calls to your test1 function and an old function )
The only way to do this is using the magic __call. You need to make all methods private so they are not accessable from the outside. Then define the __call method to handle the method calls. In __call you then can execute whatever function you want before calling the function that was intentionally called.
Lets have a go at this one :
class test
{
function __construct()
{
}
private function test1()
{
echo "In test1";
}
private function test2()
{
echo "test2";
}
private function test3()
{
echo "test3";
}
function CallMethodsAfterOne($methods = array())
{
//Calls the private method internally
foreach($methods as $method => $arguments)
{
$this->test1();
$arguments = $arguments ? $arguments : array(); //Check
call_user_func_array(array($this,$method),$arguments);
}
}
}
$test = new test;
$test->CallMethodsAfterOne('test2','test3','test4' => array('first_param'));
Thats what I would do

Get line and file where object is created in PHP

Is it possible to get the line and file where a object is created?
For example.
I know the print PHP error outputs where a error occurred and at which line. Is it possible to use that mechanism?
Sending the file to the object is easy. I can just use basename(__FILE__) as an argument. But I would prefer if the object arguments can remain empty. Like this:
Foo.php
<?php
class Foo {
public $line = null;
public function __construct(){
$this->line = where_object_is_assigned
}
}
?>
Index.php
<?php
$object = new Foo();
echo $object->line // Output Index.php line 3
?>
Is there a way for the object to access this data without sending it?
Thanks in advance
I solved it by using the function debug_backtrace();
<?php
class Foo {
public $line = null;
public function __construct(){
$bt = debug_backtrace();
$caller = array_shift($bt); // Get first array
$this->line = $caller["line"];
}
}
?>
Index.php
<?php
$object = new Foo();
echo $object->line // Output: 3
?>
The function must be used in __construct() else it won't work.
Read more here: http://php.net/manual/en/function.debug-backtrace.php
This will output on which line-number the object is created
Class
class Foo {
public $line = NULL;
public function __construct($line){
$this->line = $line;
}
}
Index.php
<?php
$object = new Foo(__LINE__); //Will output 1
echo $object->line;
PHP provides a large number of predefined constants to any script which it runs. Within this you can simply find the predefined constant named as LINE
__LINE__ The current line number of the file.
So you need to simply use the predefined constant within your code like as
<?php
class Foo {
public $line = __LINE__;
}
$object = new Foo();
echo $object->line;
?>

Using a variable as class name

I have the following:
User::model()->exists($someParamsHere);
Is there a way to make the class name 'User' dynamic? So something like this:
$className::model()->exists($someParamsHere);
But that doesn't seem to work.
I also read something about the ReflectionClass, but i'm not really sure how to use it.
I tried this, but off course the model() method is never called this way:
$reflectionMethod = new ReflectionMethod($className, 'exists');
$reflectionMethod->invoke(null, $someParamsHere);
$className::model() works with PHP 5.3 and above, if I'm not mistaken. A workaround is to use CActiveRecord::model($className). See the documentation for CActiveRecord.model().
In PHP >= 5.3 works fine:
<?php
class Foo {
static function Bar() {
return "Bar";
}
static function getFoo() {
return new static();
}
function getBar() {
return static::Bar();
}
}
$class = "Foo";
print $class::Bar() . "\n";
print $class::getFoo()->Bar() . "\n";
Result:
Bar
Bar

Getting an error trying to initialize this public class variable using dirname() outside a method

Why can't I set a public member variable using a function?
<?
class TestClass {
public $thisWorks = "something";
public $currentDir = dirname( __FILE__ );
public function TestClass()
{
print $this->thisWorks . "\n";
print $this->currentDir . "\n";
}
}
$myClass = new TestClass();
?>
Running it yields:
Parse error: syntax error, unexpected '(', expecting ',' or ';' in /tmp/tmp.php on line 7
You cannot have expressions in the variable declarations. You can only use constant values. The dirname() may not appear in this position.
If you were to use PHP 5.3 you could use:
public $currentDir = __DIR__ ;
Otherwise you will have to initialize $this->currentDir in the __constructor.
As per the PHP manual, your instance variables:
must be able to be evaluated at
compile time and must not depend on
run-time information in order to be
evaluated
As such, you can't use the dirname function in the property initialisation. Therefore, simply use a constructor to set the default value via:
public function __construct() {
$this->currentDir = dirname( __FILE__ );
}
You cannot call functions when you specify attributes.
Use this instead:
<?php
class TestClass{
public $currentDir = null;
public function TestClass()
{
$this->currentDir = dirname(__FILE__);
/* the rest here */
}
}
Looks like you can not call functions when specifying default values for member variables.
You can't call functions to declare class variables, sadly. You could, however, assign the return value from dirname( FILE ) to $this->currentDir from within the constructor.
EDIT: Mind you: the constructor in PHP => 5 is called __construct( ), not the name of the class.
You can use this instead:
public $currentDir = '';
public function TestClass()
{
$this->currentDir = dirname( __FILE__ );
...
The dirname expression is causing the error you can not declare an expression as a variable there. You could do this though.
<?
class TestClass {
public $thisWorks = "something";
public $currentDir;
public function __construct()
{
$this->currentDir = dirname( __FILE__ );
}
public function test()
{
echo $this->currentDir;
}
}
Everytime you instantiate a new class the dirname will be set in the constructor. I also recommend omitting the closing php tag ?> in your files. Helps to alleviate and header sent errors
The reason is that you cannot assign instance variables using functions in a static manner. It is simply not allowed in PHP.
May I suggest you do this:
<?
class Foo {
public $currentDir;
public function __construct() {
$this->currentDir = dirname(__FILE__);
}
}
?>
do it in the constructor.
$this->currentDir = dirname( FILE );
and by the way
print $currentDir . "\n";
use $this when calling vars in class

Basic PHP problems

When I use this function variables created by the included scripts are retained within the scope of this function.
function reqscript($script)
{
$include_dir = 'inc/';
$page_ext = '.php';
include($include_dir.$script.$page_ext);
}
Is there any way of me not having to use the following method?
include(buildfilename('...'));
If you want to define some variables in your included file, you have to use $GLOBALS.
e.g: $foobar = 42; should be $GLOBALS['foobar'] = 42;
So $foobar is available in the global scope (outside of functions).
But I would prefer a buildfilename() method.
Your answer is on php.net already, use return at the end of your included file.
http://php.net/manual/en/function.include.php
Example #5:
return.php
<?php
$var = 'PHP';
return $var;
?>
noreturn.php
<?php
$var = 'PHP';
?>
testreturns.php
<?php
$foo = include 'return.php';
echo $foo; // prints 'PHP'
$bar = include 'noreturn.php';
echo $bar; // prints 1
?>
I suggest you adopt your code to use the buildfilename() method, like Floem suggested. However, if you can't or do not wish to do so, here's a simple wrapper to import variables to the global namespace:
class Req {
public function __construct($src) {
include($src);
foreach (get_object_vars($this) as $name => $value) {
$_GLOBALS[$name] = $value;
}
}
}
function reqscript($script) {
$include_dir = 'inc/';
$page_ext = '.php';
new Req($include_dir . $script . $page_ext);
}

Categories