include file with visibility scope - php

When we include files in PHP, they are somehow cached. So, if one contains a class definition, when we try to include it twice, we will get an error saying "Can not redeclare class".
But is it possible to get include file code invoked with a scope set to current function, let's say?
E.g. if we have two files:
moo.php:
<?php
class Moo
{
function __construct()
{
echo "hello, world!" . PHP_EOL;
}
}
?>
main.php:
<?php
function foo()
{
include("moo.php");
new Moo();
}
foo();
new Moo(); // <-- here should be an error saying "could not find class Moo"
include("moo.php");
new Moo(); // <-- and here should not
?>
As far as i've tried, not eval(file_get_contents("moo.php"));, nor namespaces either gave no expected effect with a least of code...

Use require_once() and include_once(). They'll make PHP remember what files were included, and NOT include them again elsewhere in the code. After the first include/require, subsequent ones on the same file will essentially become a null-op.

Namespaces should fix this prob -> http://php.net/manual/en/language.namespaces.php

You should try implementing autoload for your classes. It will help prevent things like this.

Seems that monkey patching did the trick:
<?php
$code = <<<EOS
namespace monkeypatch;
\$s = "moofoo";
echo "This should six, but is it?: " . strlen(\$s) . PHP_EOL;
echo "Whoa! And now it is six, right?: " . \strlen(\$s) . PHP_EOL;
function strlen(\$x)
{
return -3.14;
}
EOS;
eval($code);
echo "While out of namespaces it is still six...: " . strlen("moofoo") . PHP_EOL;
Lots of thanks to Marc B. for the hint!

Related

Register/create a named function programatically in PHP

Is it possible to programatically register/create a named function in PHP, inside the global scope?
This is possible with create_function (before PHP 7+) and nowadays it's possible with anonymous/lambda functions, but then again you either let them be invoked or you assign them to a variable or an object property, then just invoke them with () at the end.
What I'm interested if it's anyhow possible to add a new named function in a scope which does not have to be assigned to a variable and accessed with $functionName?
Some solution what I'm looking for is:
create_named_function('fullname', function($firstname, $lastname) {
return $firstname . ' ' . $lastname;
});
Then I'd have it accessible like fullname(params...).
Here example with eval:
<?php
$functionName = 'foo';
$f = '
function ' . $functionName . '($a) {
var_dump($a);
}
';
// Finger crossed!)))
eval($f);
// Now you have function "foo" in your global scope!)
$functionName('bar');
// It will print
// string(3) "bar"
But you have to have clear vision what are you really doing here... because it's really tricky place...
Not sure if it should be encouraged to do this - it stops all sort of useful things being able to check code and code completion in IDE's.
BUT...
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$body = <<< 'FN'
<?php
function fullname($firstname, $lastname) {
return $firstname . ' ' . $lastname;
}
FN;
file_put_contents("func.php", $body);
require "func.php";
echo fullname("Joe", "Bloggs");
The first part creates an include file with the required code (note the use of Nowdoc string, which allows the inclusion of variables without them being substituted). This could be any form of code generation.

Does setting $this = &$otherObject change anything?

The comments indicate that I have to clarify my point: I'm a developer and consultant working on foreign code here. My current assignment is to help migrating an existing (very large) system from PHP4 to Java. While reviewing the code I stumbled across a piece of code that quite confuses me.
Some class (let's call it TestClass) in the system I'm working on does something like this:
function reload(){
$newobject = new TestClass();
$this = $newobject;
}
I gave it a quick try, expecting some inconsistent behavior between accessing members of the object directly or via some getter in case this somehow works. I thought that at worst the external pointers to the existing object and the internal one (aka $this) would target different portions of the heap.
Quick tests seem to indicate that simply nothing happens.
Any idea if this has any (side) effect whatsoever?
Here is my complete test:
<?php
ini_set('display_errors', true);
class TestClass{
var $var1;
function TestClass(){
$this->var1 = 0;
}
function getVar1(){
return $this->var1;
}
function setVar1($value){
$this->var1 = $value;
}
function reload(){
$newobject = new TestClass();
$this = &$newobject;
}
}
echo "<h3>Creating TestObject</h3>";
$testObject = new TestClass();
echo "Accessing member directly: " . $testObject->var1 . "<br>";
echo "Accessing member via get: " . $testObject->getVar1() . "<br>";
echo "Setting member directly to 1<br>";
$testObject->var1 = 1;
echo "Accessing member directly: " . $testObject->var1 . "<br>";
echo "Accessing member via get: " . $testObject->getVar1() . "<br>";
echo "<h3>Calling reload</h3>";
$testObject->reload();
echo "Accessing member directly: " . $testObject->var1 . "<br>";
echo "Accessing member via get: " . $testObject->getVar1() . "<br>";
?>
I expected to get 1 and 0 at last two calls if $this now pointed towards the new object while $testObject would still point to the original one, but 1 is returned in both cases. So I need to know whether the reassignment of $this is doing anything but being a bad idea. If not I can dump that part for good. So if anyone knows of any side effects please tell.
PS: I am fully aware that the above code is not using visibility and such. The original system is written in PHP4 so why bother :-|
Okay, with the hint of a colleague I got it. If the reload function is changed to
function reload(){
$newobject = new TestClass();
$this = $newobject;
}
the object is overwritten with the content of the newly created one. This is due to the copy on write mentioned by "i put on my robe an wizard hat" in the comment above. If used with the forced call-by-reference nothing happens which is good.

Class not found PHP OOP

I can't get this to work.
<?php
function __autoload($classname){
include 'inc/classes/' . $classname . '.class.php';
}
__autoload("queries")
$travel = new queries();
echo $travel->getPar("price");
?>
And this is the inc/classes/queries.class.php file.
<?
class queries {
function getPar($par, $table='travel', $type='select') {
$result = $db->query("
$type *
FROM $table
WHERE
$par LIKE
");
while ($row = $result->fetch_assoc()) {
return "
$row[$par]
";
}
}
}
?>
It returns "Class 'queries' not found". What's wrong with it?
EDIT:
Fatal error: Cannot redeclare __autoload() (previously declared in /index.php:5) in /index.php on line 5
What the hell? I can't redeclare a function that is already declared in its own line, why?
Try so (without class autoload):
function __autoload($classname){
include_once 'inc/classes/' . $classname . '.class.php';
}
$travel = new queries();
Also see this link
Instead of that dreadful abomination, you should learn how to utilize spl_autoload_register():
spl_autoload_register( function( $classname ){
$filename = 'inc/classes/' . $classname . '.class.php';
if ( !file_exists( $filename) ){
throw new Exception("Could not load class '$classname'.".
"File '$filename' was not found !");
}
require $filename;
});
And you should register the autoloader in your index.php or bootstrap.php file, and do it only once per loader (this ability lets you define multiple loaders, but that's used, when you have third party library, which has own autoloader .. like in case of SwiftMailer).
P.S. please learn to use prepared statements with MySQLi or PDO.
Update
Since you are just now learning OOP, here are few things, which you might find useful:
Lectures:
Advanced OO Patterns
Inheritance, Polymorphism, & Testing
Recognizing smelly code
Global State and Singletons
Don't Look For Things!
Books:
PHP Object-Oriented Solutions
Patterns of Enterprise Application Architecture
remove this line from you code __autoload("queries"), you don't need to call autoloader it will be called by it self whenever it encounters any undeclared class and use require_once instead of include and debug if you paths are correct or not.

Hook a PHP existing function to trigger a function when called

For MVC reasons, I want to be able to trigger a function to find when the function has been called, since Codeigniter has functions around their core, I want to hook a function such as setcookie and create a file when it's been called (from the triggered function) for example:
function call_me()
{
$file = fopen('setcookie.txt', 'a+');
fwrite($file, 'Called at ' . __CLASS__);
fclose();
}
So when setcookie is called, it should trigger the call_me function. Is there any specific function or method to do this? I know about debug_backtrace but that's not the purpose I want.
What you basically need to have a look at is Observers.
The observer pattern (aka. Dependents, publish/subscribe) is a
software design pattern in which an object, called the subject,
maintains a list of its dependents, called observers, and notifies
them automatically of any state changes, usually by calling one of
their methods. It is mainly used to implement distributed event
handling systems. Observer is also a key part in the familiar MVC
architectural pattern. In fact the observer pattern was first
implemented in Smalltalk's MVC based user interface framework.1
Why don't you try what is described here :
http://devzone.zend.com/1384/observer-pattern-in-php/
I know about debug_backtrace but that's not the purpose I want.
I see that you insist not to use backtrack function, but still I believe that when you want to log when a function is called backtrack can come in handy.
The idea is that you have a predifined piece pf code stored in a constant, whenever you want to debug an if condition evaluates this code.
If you are under prouction the if statement will prevent from evaluating anything so your code's speed is not affected. If it works for you you can modify it to your needs, to track down even more levels.
To make my point this is a full example, if I have not understood right and this is not what you're looking for, my apologies!
To check the example you have a file: test.php
<?php
define ('__SITE_PATH',realpath(dirname(__FILE__)).'/');
ini_set('log_errors', 1);
ini_set('error_log', __SITE_PATH.'my_error_log.log');
include 'test1.php';
include 'test2.php';
define (__DEBUG_EVAL, '
$dbt = debug_backtrace();
error_log(
"\n".
"Parent function file: " . $dbt[1]["file"] . "\n" .
"Parent function class: " . $dbt[2]["class"] . "\n" .
"Parent fiunction name: " . $dbt[2]["function"] . "\n" .
"Par. fiunc. called from line: " . $dbt[2]["line"] . "\n" .
"Child function file: " . $dbt[0]["file"] . "\n" .
"Child function class: " . $dbt[1]["class"] . "\n" .
"Child fiunction name: " . $dbt[1]["function"] . "\n" .
"Child fiunc. called from line: " . $dbt[1]["line"] . "\n" .
"\n"
);
');
test1::a();
?>
This is test1.php
<?PHP
class test1
{
public static function a()
{
test2::b();
}
}
?>
The last is test2.php
<?PHP
class test2
{
public static function b()
{
if(defined('__DEBUG_EVAL')) eval(__DEBUG_EVAL);
echo 'Hello!';
}
}
?>
This is the result:
[13-Apr-2012 14:37:18]
Parent function file: C:\PHP-GTK\MyProjects\Electre\test1.php
Parent function class: test1
Parent fiunction name: a
Par. fiunc. called from line: 29
Child function file: C:\PHP-GTK\MyProjects\Electre\test2.php
Child function class: test2
Child fiunction name: b
Child fiunc. called from line: 7

run function block in context of global namespace in PHP

So the senario is that I want to have a custom function for requiring libraries. Something like:
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
}
The problem being that require and require_once will load the files into the namespace of the function, which doesn't help for libraries of functions, classes, et cetera. So is there a way to do this?
(Something avoiding require and require_once altogether is fine, as long as it doesn't use eval since it's banned on so many hosts.)
Thanks!
Technically include() is meant to act as though you're inserting the text of included script at that point in your PHP. Thus:
includeMe.php:
<?php
$test = "Hello, World!";
?>
includeIt.php:
<?php
include('includeMe.php');
echo $test;
?>
Should be the exact same as:
<?php
/* INSERTED FROM includeMe.php */
$test = "Hello, World!";
/* END INSERTED PORTION */
echo $test;
?>
Realizing this, the idea of making a function for dynamically including files makes about as much sense (and is about as easy to do) as having dynamic code all-together. It's possible, but it will involve a lot of meta-variables.
I'd look into Variable Variables in PHP as well as the get_defined_vars function for bringing variables into the global scope. This could be done with something like:
<?php
define('E_ROOT', str_replace('//','/',dirname(__FILE__)));
/* ... */
function e_load($fn, $allowReloading = FALSE) {
$prev_defined_vars = get_defined_vars();
$inc = E_ROOT.'/path/here/'.$fn.'.php';
if($allowReloading)
require $inc; // !!!
else
require_once $inc; // !!!
$now_defined_vars = get_defined_vars();
$new_vars = array_diff($now_defined_vars, $prev_defined_vars);
for($i = 0; $i < count($new_vars); $i++){
// Pull new variables into the global scope
global $$newvars[$i];
}
}
?>
It may be more convenient to just use require() and require_once() in place of e_load()
Note that functions and constants should always be in the global scope, so no matter where they are defined they should be callable from anywhere in your code.
The one exception to this is functions defined within a class. These are only callable within the namespace of the class.
EDIT:
I just tested this myself. Functions are declared in the global scope. I ran the following code:
<?php
function test(){
function test2(){
echo "Test2 was called!";
}
}
//test2(); <-- failed
test();
test2(); // <-- succeeded this time
?>
So the function was only defined after test() had been run, but the function was then callable from outside of test(). Therefore the only thing you should need to pull into the global scope are your variables, via the script I provided earlier.
require_once E_ROOT.$libName.'.php';
KISS
Instead of doing this...
$test = "Hello, World!";
... you could consider doing this ...
$GLOBALS[ 'test' ] = "Hello, World!";
Which is safe and consistent in both local function context, and global include context. Probably not harmful to visually remind the reader that you are expecting $test to become global. If you have a large number of globals being dragged in by your libraries maybe there's justification for wrapping it in a class (then you have the benefit of spl_autoload_register which kind of does what you are doing anyhow).

Categories