I'm trying to create a class TestClass that's divided over several files. I have split it over 3 files where the first file TestClassPart1.php has the start of the class class TestClass { and the last file TestClassPart3.php has the closing bracket of the class. These are the 3 files
//TestClassPart1.php
<?php
class TestClass {
public function func1(){
echo "func 1";
}
//TestClassPart2.php
<?php
public function func2(){ echo "func 2"; }
//TestClassPart3.php
<?php
public function func3(){ echo "func 3"; }
}
I then recombine in the actual class file called TestClass.phpso TestClass.php is just the glue of all 3 files.
<?php
require 'TestClassPart1.php';
require 'TestClassPart2.php';
require 'TestClassPart3.php';
I thought this should work, but when I try to create an instance of TestClass and call one of the functions, I get parse error, expecting T_FUNCTION' in C:\wamp\www\TestClassPart1.php on line 5. Line 5 is the } of func1()
<?php
require 'TestClass.php';
$nc = new TestClass();
$nc->func1();
Shouldn't this work? I thought you could spread a class over several files no problem. Am I doing it wrong?
When you require a file, PHP will parse and evaluate the contents.
You class is incomplete, so when PHP parses
class TestClass {
public function func1(){
echo "func 1";
}
it's not able to make sense of the class, because the closing } is missing.
Simple as that.
And to anticipate your next question. This
class Foo
{
include 'methods.php'
}
will not work either.
From the PHP Manual on OOP 4 (couldnt find it in 5)
You can NOT break up a class definition into multiple files. You also can NOT break a class definition into multiple PHP blocks, unless the break is within a method declaration. The following will not work:
<?php
class test {
?>
<?php
function test() {
print 'OK';
}
}
?>
However, the following is allowed:
<?php
class test {
function test() {
?>
<?php
print 'OK';
}
}
?>
If you are looking for Horizontal Reuse, either wait for PHP.next, which will include Traits or have a look at
Can I include code into a PHP class?
I had this same thought a while back as a purely academic interest. It's not directly possible to do what you're asking, although you are able to use PHP to produce PHP that then gets evaluated by the server.
Long story short:
Don't bother
Short story long:
it adds a level of insecurity to your classing system as it becomes harder to control file access.
it slows down the compilation/caching of pages
you really don't need to force a square peg into a round hole.
Instead: use proper OOP practices of separating functionality into classes and extending existing classes.
If you must do it this way, you can use include_once() to directly shove a file into your script.
Related
I would like just to like to ask for a little elucidation about this three code snippets I found and how PHP behaves with them:
1) a php class (tmp.class.php) with a static method call:
<?php
class Dummy {
public function sayHello()
{
echo "HELLO FROM DUMMY";
}
public static function requireScript() {
require __DIR__ . "/tmp2.php";
}
}
Dummy::requireScript();
2) another file (tmp1.php), instantiating the previous defined class:
<?php
require_once __DIR__. "/tmp.class.php";
$obj = new Dummy;
?>
3) another file (tmp2.php), using the previous instance of the class:
<?php
require_once __DIR__ ."/tmp1.php";
$obj->sayHello();
?>
Now I know that as the requireScript() method has a require call in it, in fact the tmp2.php is included twice, am I right? But when I make the script run (open the tmp2.php file in the browser) I get a Notice: Undefined variable: obj and then of course a Fatal error because of the sayHello();
Shouldn't the $obj be available to the second required tmp2.php script? What is wrong with this code?
Thanks for attention!
In fact noone should build PHP application in that way. You shouldn't put require / include in many files. In simple application you should run require / include at the beginning of file to have everything you need. In more complex applications you should simple use Object Oriented Programming and use autoloader to load classes definitions when they are needed
Here is a very simple and silly question I'm going to ask:
I'm very new to PHP, I was wondering if there is a way to call just a function in a class of PHP by AJAX.
for instance something like this:
$.ajax({
url:'newPHPClass.php/My_Function_Name'
...
});
So in php, it would be like:
<?php
class newPHPClass {
function My_Function_Name(){
}
}
?>
Why do I need this? So I wouldn't have like so many php files. Instead I'll have a single php class with different functions inside. It will look cleaner and less extra files.
I have used ASP.NET MVC C# before. and in ASP.NET I could just simply put my controller's name in the URL section of AJAX followed by / and then my function's name (which could be modified in my Global.asax.cs file).
Thanks.
<?php
$action = $_POST['action'];
class Foo {
function execute($action) {
switch($action) {
case "method1":
$this->doMethod1();
break;
case "method2":
$this->doMethod2();
break;
}
}
function doMethod1() {
echo "Foo::doMethod1";
}
function doMethod2() {
echo "Foo::doMethod2";
}
}
$foo = new Foo();
$foo->execute($action);
?>
And use foo.php?action=method1 as URL.
First of all you don't call functions or methods via AJAX, you make a request to a page.
If you make an AJAX call to a PHP file like:
<?php
class newPHPClass {
function My_Function_Name(){
}
}
?>
nothing will be returned and nothing will happen server side other than allocating the space for that class and then immediately destroy it at the end of the request.
For your question: it doesn't really matter on the client side (Javascript) how you are going to manage the class and files organization: only one file is going to be requested by an AJAX call.
I'd suggest you to have at least two different files: the declaration of functions or classes and the file that manage the response. You need a bit a separation from execution and declaration, therefore I'd avoid things like:
class A { ... }
$a = new A;
$a->myMethod();
Depending on the AJAX output I'd go with something like this instead:
# class.php
class A {...}
# ajax.php
$a = new A;
$a->myMethod();
Finally a suggestion: don't use classes when they just don't make sense. Having a bunch of functions grouped inside a class doesn't really feel OOP to me. I think you are using classes with procedural code in mind. Therefore I would go with a file that declares a bunch of functions instead.
a.php
<?php
echo "AAA\n";
if(class_exists('NotImplementedException')) {
echo "BBB\n";
return;
echo "DDD\n";
}
echo "CCC\n";
/**
* Thrown when a feature is not yet implemented.
*/
class NotImplementedException extends Exception {}
b.php
<?php
include 'a.php';
include 'a.php';
When I run b.php I get:
AAA
BBB
PHP Fatal error: Cannot redeclare class NotImplementedException in /home/mark/Tests/IncludeTwice/a.php on line 15
What's going on here? The output I would expect is
AAA
CCC
(class gets declared for first time)
AAA
BBB
(execution stops)
To those saying "the interpreter scans and parses the whole file first": then why does this work?:
<?php
class A{}
if(!class_exists('A')) {
class A{}
}
I think one part is a bug...
The PHP interpreter works differently if you are extending a class.
This works:
<?php
class a {}
exit();
class a extends Exception {}
?>
This does not:
<?php
class a extends Exception {}
exit();
class a {}
?>
From what I can see in the PHP 5.4.0 source, there are two different functions that handle the binding of classes: do_bind_class:4494 for standalone classes and do_bind_inherited_class:4533 for inherited classes (ones that use the extend keyword).
The stand-alone function has a conditional that ignores duplicate class definitions at compile time in case it is never hit at runtime. The inherited class version is missing this conditional (maybe on purpose, maybe not).
I would patch the inherited function to have the same conditional, test and submit to the developers.
And the other part is a feature...
As for your conditional class piece: I believe that PHP will load your class at compile-time if it is declared at global scope, but if it is contained inside a block, it will not be loaded until it is executed.
This works:
<?php
$a = new A();
//{
class A {}
//}
?>
This doesn't work, even though it is logically identical:
<?php
$a = new A();
{
class A {}
}
?>
When you combine these two pieces of functionality, your problem arises since your class is both an inherited class and declared at global scope.
You need to move the class declaration into an else statement from the class_exists() call. You are declaring it both times that you include a.php. The return doesn't prevent the file from being parsed, which includes the class declaration in this case. So while the script execution doesn't make it past your return, PHP sees that you've declared NotImplementedException more than once.
Think of it as if you put a bunch of syntactically incorrect code after a return. The parser will still give you an error even though the code execution won't make it there.
Background:
I'm building an automated test framework for a PHP application, and I need a way to efficiently "stub out" classes which encapsulate communication with external systems. For example, when testing class X that uses DB wrapper class Y, I would like to be able to "swap in" a "fake" version of class Y while running automated tests on class X (this way I don't have to do full setup + teardown of the state of the real DB as part of the test).
Problem:
PHP allows "conditional includes", which means basically that include/require directives are handled as part of processing the "main" logic of a file, e.g.:
if (condition) {
require_once('path/to/file');
}
The problem is that I can't figure out what happens when the "main" logic of the included file calls "return". Are all of the objects (defines, classes, functions, etc.) in the included file imported into the file which calls include/require? Or does processing stop with the return?
Example:
Consider these three files:
A.inc
define('MOCK_Z', true);
require_once('Z.inc');
class Z {
public function foo() {
print "This is foo() from a local version of class Z.\n";
}
}
$a = new Z();
$a->foo();
B.inc
define('MOCK_Z', true);
require_once('Z.inc');
$a = new Z();
$a->foo();
Z.inc
if (defined ('MOCK_Z')) {
return true;
}
class Z {
function foo() {
print "This is foo() from the original version of class Z.\n";
}
}
I observe the following behavior:
$ php A.inc
> This is foo() from a local version of class Z.
$ php B.inc
> This is foo() from the original version of class Z.
Why This is Strange:
If require_once() included all of the defined code objects, then "php A.inc" ought to complain with a message like
Fatal error: Cannot redeclare class Z
And if require_once() included only the defined code objects up to "return", then "php B.inc" ought to complain with a message like:
Fatal error: Class 'Z' not found
Question:
Can anyone explain exactly what PHP is doing, here? It actually matters to me because I need a robust idiom for handling includes for "mocked" classes.
According to php.net, if you use a return statement, it'll return execution to script that called it. Which means, require_once will stop executing, but the overall script will keep running. Also, examples on php.net show that if you return a variable within an included file, then you can do something like $foo = require_once('myfile.php'); and $foo will contain the returned value from the included file. If you don't return anything, then $foo is 1 to show that require_once was successful. Read this for more examples.
And I don't see anything on php.net that says anything specifically about how the php interpreter will parse included statements, but your testing shows that it first resolves class definitions before executing code in-line.
UPDATE
I added some tests as well, by modifying Z.inc as follows:
$test = new Z();
echo $test->foo();
if (defined ('MOCK_Z')) {
return true;
}
class Z {
function foo() {
print "This is foo() from the original version of class Z.\n";
}
}
And then tested on the command line as follows:
%> php A.inc
=> This is foo() from a local version of class Z.
This is foo() from a local version of class Z.
%> php B.inc
=> This is foo() from the original version of class Z.
This is foo() from the original version of class Z.
Obviously, name hoisting is happening here, but the question remaining is why there are no complaints about re-declarations?
UPDATE
So, I tried to declare class Z twice in A.inc and I got the fatal error, but when I tried to declare it twice in Z.inc, I didn't get an error. This leads me to believe that the php interpreter will return execution to the file that did the including when a fatal runtime error occurs in an included file. That is why A.inc did not use Z.inc's class definition. It was never put into the environment, because it caused a fatal error, returning execution back to A.inc.
UPDATE
I tried the die(); statement in Z.inc, and it actually does stop all execution. So, if one of your included scripts has a die statement, then you will kill your testing.
Okay so behavior of the return statement in PHP included files is to return control to the parent in execution. That means the classes definitions are parsed and accessible during the compile phase. For instance, if you change the above to the following
a.php:
<?php
define('MOCK_Z', true);
require_once('z.php');
class Z {
public function foo() {
print "This is foo() from a local version of class Z in a.php\n";
}
}
$a = new Z();
$a->foo();
?>
b.php:
<?php
define('MOCK_Z', true);
require_once('z.php');
$a = new Z();
$a->foo();
?>
z.php:
<?php
if (defined ('MOCK_Z')) {
echo "MOCK_Z definition found, returning\n";
return false;
}
echo "MOCK_Z definition not found defining class Z\n";
class X { syntax error here ; }
class Z {
function foo() {
print "This is foo() from the original version of class Z.\n";
}
}
?>
then php a.php and php b.php will both die with syntax errors; which indicates that the return behavior is not evaluated during compile phase!
So this is how you go around it:
z.php:
<?php
$z_source = "z-real.inc";
if ( defined(MOCK_Z) ) {
$z_source = "z-mock.inc";
}
include_once($z_source);
?>
z-real.inc:
<?php
class Z {
function foo() {
print "This is foo() from the z-real.inc.\n";
}
}
?>
z-mock.inc:
<?php
class Z {
function foo() {
print "This is foo() from the z-mock.inc.\n";
}
}
?>
Now the inclusion is determined at runtime :^) because the decision is not made until $z_source value is evaluated by the engine.
Now you get desired behavior, namely:
php a.php gives:
Fatal error: Cannot redeclare class Z in /Users/masud/z-real.inc on
line 2
and php b.php gives:
This is foo() from the z-real.inc.
Of course you can do this directly in a.php or b.php but doing the double indirection may be useful ...
NOTE
Having SAID all of this, of course this is a terrible way to build stubs hehe for unit-testing or for any other purpose :-) ... but that's beyond the scope of this question so I shall leave it to your good devices.
Hope this helps.
It looks like the answer is that class declarations are compile-time, but duplicate class definition errors are run-time at the point in the code that the class is declared. The first time a class definition is in a parsed block, it is immediately made available for use; by returning from an included file early, you aren't preventing class declaration, but you are bailing out before the error is thrown.
For example, here are a bunch of class definitions for Z:
$ cat A.php
<?php
error_reporting(-1);
$init_classlist = get_declared_classes();
require_once("Z.php");
var_dump(array_diff(get_declared_classes(), $init_classlist));
class Z {
function test() {
print "Modified Z from A.php.\n";
}
}
$z = new Z();
$z->test();
return;
class Z {
function test() {
print "Another Z from A.php.\n";
}
}
$ cat Z.php
<?php
echo "In Z.php!\n";
return;
class Z {
function test() {
print "Original Z.\n";
}
}
When A.php is called, the following is produced:
In Z.php!
array(0) {
}
Modified Z from A.php.
This shows that the declared classes don't change upon entering Z.php - the Z class is already declared by A.php further down the file. However, Z.php never gets a change to complain about the duplicate definition due to the return before the class declaration. Similarly, A.php doesn't get a chance to complain about the second definition in the same file because it also returns before the second definition is reached.
Conversely, removing the first return; in Z.php instead produces:
In Z.php!
Fatal error: Cannot redeclare class Z in Z.php on line 4
By simply not returning early from Z.php, we reach the class declaration, which has a chance to produce its run-time error.
In summary: class declaration is compile-time, but duplicate definition errors are run-time at the point the class declaration appears in the code.
(Of course, having not confirmed this with the PHP internals, it might be doing something completely different, but the behavior is consistent with my description above. Tested in PHP 5.5.14.)
This is the closest thing I could find in the manual:
If there are functions defined in the included file, they can be used in the main file independent if they are before return() or after. If the file is included twice, PHP 5 issues fatal error because functions were already declared, while PHP 4 doesn't complain about functions defined after return().
And this is true regarding functions. If you define the same function in A and Z (after the return) with PHP 5, you'll get a fatal error as you expect.
However, classes seem to fall back to PHP 4 behavior, where it doesn't complain about functions defined after return. To me this seems like a bug, but I don't see where the documentation says what should happen with classes.
I've thought about this for a while now, and nobody has been able to point me to a clear and consistent explanation for the way PHP (up to 5.3 anyway) processes includes.
I conclude that it would be better to avoid this issue entirely and achieve control over "test double" class substitution via autoloading:
spl-autoload-register
In other words, replace the includes at the top of each PHP file with a require_once() which "bootstraps" a class which defines the logic for autoloading. And when writing automated tests, "inject" alternative autoloading logic for the classes to be "mocked" at the top of each test script.
It will naturally require a good deal of effort to modify existing code to follow this approach, but the effort appears to be worthwhile both to improve testability and to reduce the total number of lines in the codebase.
Can you declare a function like this...
function ihatefooexamples(){
return "boo-foo!";
};
And then redeclare it somewhat like this...
if ($_GET['foolevel'] == 10){
function ihatefooexamples(){
return "really boo-foo";
};
};
Is it possible to overwrite a function that way?
Any way?
Edit
To address comments that this answer doesn't directly address the
original question. If you got here from a Google Search, start here
There is a function available called override_function that actually fits the bill. However, given that this function is part of The Advanced PHP Debugger extension, it's hard to make an argument that override_function() is intended for production use. Therefore, I would say "No", it is not possible to overwrite a function with the intent that the original questioner had in mind.
Original Answer
This is where you should take advantage of OOP, specifically polymorphism.
interface Fooable
{
public function ihatefooexamples();
}
class Foo implements Fooable
{
public function ihatefooexamples()
{
return "boo-foo!";
}
}
class FooBar implements Fooable
{
public function ihatefooexamples()
{
return "really boo-foo";
}
}
$foo = new Foo();
if (10 == $_GET['foolevel']) {
$foo = new FooBar();
}
echo $foo->ihatefooexamples();
Monkey patch in namespace php >= 5.3
A less evasive method than modifying the interpreter is the monkey patch.
Monkey patching is the art of replacing the actual implementation with a similar "patch" of your own.
Ninja skills
Before you can monkey patch like a PHP Ninja we first have to understand PHPs namespaces.
Since PHP 5.3 we got introduced to namespaces which you might at first glance denote to be equivalent to something like java packages perhaps, but it's not quite the same. Namespaces, in PHP, is a way to encapsulate scope by creating a hierarchy of focus, especially for functions and constants. As this topic, fallback to global functions, aims to explain.
If you don't provide a namespace when calling a function, PHP first looks in the current namespace then moves down the hierarchy until it finds the first function declared within that prefixed namespace and executes that. For our example if you are calling print_r(); from namespace My\Awesome\Namespace; What PHP does is to first look for a function called My\Awesome\Namespace\print_r(); then My\Awesome\print_r(); then My\print_r(); until it finds the PHP built in function in the global namespace \print_r();.
You will not be able to define a function print_r($object) {} in the global namespace because this will cause a name collision since a function with that name already exists.
Expect a fatal error to the likes of:
Fatal error: Cannot redeclare print_r()
But nothing stops you, however, from doing just that within the scope of a namespace.
Patching the monkey
Say you have a script using several print_r(); calls.
Example:
<?php
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
But you later change your mind and you want the output wrapped in <pre></pre> tags instead. Ever happened to you?
Before you go and change every call to print_r(); consider monkey patching instead.
Example:
<?php
namespace MyNamespace {
function print_r($object)
{
echo "<pre>", \print_r($object, true), "</pre>";
}
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
}
Your script will now be using MyNamespace\print_r(); instead of the global \print_r();
Works great for mocking unit tests.
nJoy!
Have a look at override_function to override the functions.
override_function — Overrides built-in
functions
Example:
override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
short answer is no, you can't overwrite a function once its in the PHP function scope.
your best of using anonymous functions like so
$ihatefooexamples = function()
{
return "boo-foo!";
}
//...
unset($ihatefooexamples);
$ihatefooexamples = function()
{
return "really boo-foo";
}
http://php.net/manual/en/functions.anonymous.php
You cannot redeclare any functions in PHP. You can, however, override them. Check out overriding functions as well as renaming functions in order to save the function you're overriding if you want.
So, keep in mind that when you override a function, you lose it. You may want to consider keeping it, but in a different name. Just saying.
Also, if these are functions in classes that you're wanting to override, you would just need to create a subclass and redeclare the function in your class without having to do rename_function and override_function.
Example:
rename_function('mysql_connect', 'original_mysql_connect' );
override_function('mysql_connect', '$a,$b', 'echo "DOING MY FUNCTION INSTEAD"; return $a * $b;');
I would include all functions of one case in an include file, and the others in another include.
For instance simple.inc would contain function boofoo() { simple } and really.inc would contain function boofoo() { really }
It helps the readability / maintenance of your program, having all functions of the same kind in the same inc.
Then at the top of your main module
if ($_GET['foolevel'] == 10) {
include "really.inc";
}
else {
include "simple.inc";
}
You could use the PECL extension
runkit_function_redefine — Replace a function definition with a new implementation
but that is bad practise in my opinion. You are using functions, but check out the Decorator design pattern. Can borrow the basic idea from it.
No this will be a problem.
PHP Variable Functions
Depending on situation where you need this, maybe you can use anonymous functions like this:
$greet = function($name)
{
echo('Hello ' . $name);
};
$greet('World');
...then you can set new function to the given variable any time
A solution for the related case where you have an include file A that you can edit and want to override some of its functions in an include file B (or the main file):
Main File:
<?php
$Override=true; // An argument used in A.php
include ("A.php");
include ("B.php");
F1();
?>
Include File A:
<?php
if (!#$Override) {
function F1 () {echo "This is F1() in A";}
}
?>
Include File B:
<?php
function F1 () {echo "This is F1() in B";}
?>
Browsing to the main file displays "This is F1() in B".