Fatal error with function - php

When I create the object SearchResult, I have the constructor call 'setStandardsTable' function that sets variable 'standardsTable'. For some reason I get the error
Fatal error: Uncaught Error: Call to undefined function
setStandardsTable()...
and
Error: Call to undefined function setStandardsTable()...
I tried returning the value after each variable declaration but still nothing. Below is my code.
class SearchResult {
private $keyword, $standardsTable;
/*Constructor */
public function __construct($subject, $keyword) {
//selects the standards table to query based on subject selected
$this->standardsTable = setStandardsTable($subject);
//sets the keyword that will be used to search in the Standards table selected
$this->keyword = $keyword;
}
private function setStandardsTable($subj) {
$standardsSelected="";
switch($subj) {
case "General Math":
$standardsSelected = "math_standards_eng";
break;
case "Algebra I":
$standardsSelected ="algebra_standards_eng";
break;
case "Algebra II":
$standardsSelected = "algebra_two_standards_eng";
break;
default:
$standardsSelected = "math_standards_eng";
}
return $standardsSelected;
}
}

In PHP, you need to use self:: and $this-> to call functions within the same class:
Call to a static function:
$variable = self::SomeStaticFunction();
Call to a non-static function:
$variable = $this->FunctionThatIsntStatic();
...instead of just the function name, which is expected to be in the global namespace.
$this->standardsTable = SomeFunction();
In your case: It's $this->setStandardsTable($subject);

It seems that you just have to do a minor change just replace
$this->standardsTable = setStandardsTable($subject);
With
$this->standardsTable = $this->setStandardsTable($subject);

You can not call directly a member function of Class, you should specify object to call member function.
Simply you can using $this->setStandardsTable($subject)

As others mentions you have to call it with $this
$this->standardsTable = $this->setStandardsTable($subject);
That said something others failed to mention that i think would be of great benifit would be to instead use a factory method. So instead of one overwhelming class you would make many.
interface SearchResultInterface{
public function setKeyword($keyword);
public function getKeyword();
public function getTable();
}
abstract AbstractSearchResult impliments SearchResultInterface{
protected $keyword;
public function setKeyword($keyword)
{
$this->keyword = $keyword;
}
public function getKeyword(){
return $this->keyword;
}
abstract function getTable();
}
class MathResults extends AbstractSearchResult{
public function getTable(){
return 'math_standards_eng';
}
}
class SearchResultFactory {
static function createResult($subj, $keyword) {
switch($subj) {
case "Algebra I":
$Result = new AlgebraResults();
break;
case "Algebra II":
$Result = new AlgebraIIResults();
break;
case "General Math":
default:
$Result = new MathResults();
}
$Result->setKeyword( $keyword );
return $Result;
}
}
Now the really big advantage here is that these look like they would include the lesser classes functionallity. So for example AlgebraII could include stuff from Algebra which could include stuff from Math.
So when you add these other classes in:
class AlgebraResults extends MathResults{
public function getTable(){
return 'algebra_standards_eng';
}
}
class AlgebraIIResults extends AlgebraResults{
public function getTable(){
return 'algebra_two_standards_eng';
}
}
Or you could just extend AbstractSearchResult instead of the level above it, as I have done.
So rather or not this makes sense in your use case, I don't know. But if you have a bunch of functionality you need to impliment, it may be much more streamlined to break this up some.
That said, don't break them up for the sake of breaking them up. If the functionality is generally the same and the code-base is small, then there probably isn't a need. But if you find yourself coding things wildly different for Algebra and Math, then it might make sense to separate them.
The main advantage you git from this, is smaller more focused classes/files (each class should be in its own file). Later it will be easier to add stuff, like if you add Calculus then you just add a new class in and don't have to edit the existing code much. etc.
Hope that makes sense.

Related

PHP: Shorthand Switch

I'm looking for more comfortable/more short version of Switch() statement in case of using multiple functions.
I'll give you one example: imagine 100-200 functions in one class, and you want to call only one of them by setting value to id in that class.
In my particular case, I have the following structure of PHP file:
<?php
class _main
{
function request($id)
{
switch($id)
{
case 0:
$this->writeA();
break;
case 1:
$this->writeB();
break;
///...
// then we have 100-200 functions like this in switch.
}
}
function writeA()
{
echo('a');
}
function writeB()
{
echo('b');
}
}
$id = 1;
$x = new _main();
$x->request($id);
?>
For some of you it may seem weird, but I don't want to have that much lines of code with case and break. For me, they are just making code more difficult to read.
(by the way, writing it 100 times will not making it fun for me too).
CONCLUSION
What could be the best,fast and comfortable method?
Can I store functions to array and then call them?
And will it affect performance? Will be Swicth() even faster?
Thank you :)
EDIT
Perhaps there is a different way of thinking/coding and not only array/switch thing.
I can't say I would ever recommend this but if you really want that many methods within a single class and a singular function to route the calls through...
<?php
class MyClass
{
public $id;
public function callFunction()
{
$funcName = 'execute' . $this->id;
return $this->$funcName();
}
private function execute1()
{
echo 'execute1() Called.';
}
private function execute2()
{
echo 'execute2() Called.';
}
}
$c = new MyClass();
$c->id = 1;
$c->callFunction();
Output:
execute1() Called.
I feel like there is most likely another way to approach this with more information utilising Interfaces and Abstract classes, but with the information to go off the above might suffice your requirement.
Edit: Sadly I don't have the time right now to come up with a detailed solution, and I don't really have enough information to go off but perhaps utilising interfaces is your best solution for your requirement. Below is a very quick example.
<?php
interface WritableInterface
{
public function write($data);
}
class VersionOneWriter implements WritableInterface
{
public function write($data)
{
return $data . '<br/>';
}
}
class VersionTwoWriter implements WritableInterface
{
public function write($data)
{
return $data . $data . '<br/>';
}
}
class MyMainClass
{
public function request(WritableInterface $writer, $data)
{
return $writer->write($data);
}
}
$c = new MyMainClass();
$w1 = new VersionOneWriter();
$w2 = new VersionTwoWriter();
echo $c->request($w1, 'DataString');
echo $c->request($w2, 'DataString');
Essentially when you call your request function you pass along a Writer class which implements the WritableInterface. Anything that implements that interface has to have a write() method.
Now when you pass your data across with your method, since you are also passing a writer along that can handle the data you can safely call ->write($data) within your request() method and the result will be dependent on the class you passed through.
If you ever need another method of writing you can just add create another class that implements your interface
Hopefully that made some sense, it was a bit of a ramble as I have to disappear for a bit. If you have any questions I'll try to check back when I have time.
--
Edit2:
The define() in this instance requires PHP7+ since I'm defining an array, but you could prior to PHP7 you could just use a standard array. $classMap = ['FirstClass', 'SecondClass'];
interface MyInterface {}
class FirstClass implements MyInterface {}
class SecondClass implements MyInterface {}
$requestParam = 1;
define('CLASS_MAP', array(
'FirstClass',
'SecondClass',
));
$classMap = CLASS_MAP[$requestParam]; // SecondClass
$class = new $classMap;
var_dump($class); // Dumps out: object(SecondClass)#1 (0) {}

Pondering implementation: Instantiate class based on constant without reflection

Second update
I think I've been approaching this problem from the wrong side of the coin. Would I be correct in assuming that I should be making 'First' an abstract class and just finding a way to reference 'Second' and 'Third' at a later time?
Update
Based on some of the feedback, I have added some content to try and clear up what I would like to do. Something similar to this effect.
I know from just looking at the code below that, it is a waste of performance "if" it did work and because it doesn't, know I am approaching the problem from the wrong angle.The end objective isn't all to uncommon at a guess from some of the frameworks I've used.
I'm more trying to base this particular bit of code on the CodeIgniter approach where you can define (what below) is STR_CLASS_NAME in a config file and then at any point through the operation of the program, use it as i have dictated.
STR_CLASS_NAME = 'Second';
class First {
protected $intTestOne = 100;
public function __construct() {
$strClassName = STR_CLASS_NAME;
return new $strClassName();
}
public function TestOne() {
echo $this->intTestOne;
}
protected function TestThreePart() {
return '*Drum ';
}
}
class Second extends First{
/* Override value to know it's working */
protected $intTestOne = 200;
/* Overriding construct to avoid infinite loop */
public function __construct() {}
public function TestTwo() {
echo 'Using method from extended class';
}
public function TestThree() {
echo $this->TestThreePart().'roll*';
}
}
$Test = new First();
$Test->TestOne(); <-- Should echo 200.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum roll*'
You may be asking, why do this and not just instantiate Second, well, there are cases when it is slightly different:
STR_CLASS_NAME = 'Third';
class Third extends First{
/* Override value to know it's working */
protected $intTestOne = 300;
/* Overriding construct to avoid infinite loop */
public function __construct() {}
public function TestTwo() {
echo 'Using method from extended class';
}
public function TestThree() {
echo $this->TestThreePart().'snare*';
}
}
$Test = new First();
$Test->TestOne(); <-- Should echo 300.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum snare*'
Situation
I have a an abstract class which extends a base class with the actually implementation; in this case a basic DB wrapper.
class DBConnector ()
class DBConnectorMySQLi extends DBConnector()
As you can see, MySQLi is the implementation. Now, dependant upon a value in the configuration process, a constant becomes the class name I wish to use which in this case (as shown below builds DBConnectorMySQLi.
define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);
Objective
To have a base class that can be extended to include the implementation
For the code itself not to need know what the name of the implementation actually is
To (in this case) be able to type or use a project accepted common variable to create DBConnectorMySQLi. I.E. $db or something similar. W
Issue
When it comes to actually calling this class, I would like the code to be shown as below. I was wondering whether this is at all possible without the need to add any extra syntax. On a side note, this constant is 100% guaranteed to be defined.
$DBI = new DB_CLASS();
Solution 1
I know it is possible to use a reflection class ( as discussed in THIS QUESTION) and this works via:
$DBI = new ReflectionClass(DB_CLASS);
However, this creates code that is "dirtier" than intended
Solution 2
Start the specific implementation of DBConnectorMySQLi within the constructor function of DBConnector.
define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);
class DBConnector() { public function __construct() { $this->objInterface = new DBConnectorMySQLi(); }
class DBConnectorMySQLi()
This however would result in the need to keep on "pushing" variables from one to the other
Any advice is much appreciate
You can use variables when you instantiate a class.
$classname = DB_CLASS;
$DBI = new $classname();
Source: instantiate a class from a variable in PHP?

Best practices for static constructors

I want to create an instance of a class and call a method on that instance, in a single line of code.
PHP won't allow calling a method on a regular constructor:
new Foo()->set_sth(); // Outputs an error.
So I'm using, if I can call it that, a static constructor:
Foo::construct()->set_sth();
Here's my question:
Is using static constructors like that considered a good practice and if yes, how would you recommend naming the methods for these static constructors?
I've been hesitating over the following options:
Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
Static constructors (or "named constructors") are only beneficial to prove an intention, as #koen says.
Since 5.4 though, someting called "dereferencing" appeared, which permits you to inline class instantiation directly with a method call.
(new MyClass($arg1))->doSomething(); // works with newer versions of php
So, static constructors are only useful if you have multiple ways to instantiate your objects.
If you have only one (always the same type of arguments and number of args), there is no need for static constructors.
But if you have multiple ways of instantiations, then static constructors are very useful, as it avoids to pollute your main constructor with useless argument checking, weakening languages constraints.
Example:
<?php
class Duration
{
private $start;
private $end;
// or public depending if you still want to allow direct instantiation
private function __construct($startTimeStamp = null, $endTimestamp = null)
{
$this->start = $startTimestamp;
$this->end = $endTimestamp;
}
public static function fromDateTime(\DateTime $start, \DateTime $end)
{
return new self($start->format('U'), $end->format('U'));
}
public static function oneDayStartingToday()
{
$day = new self;
$day->start = time();
$day->end = (new \DateTimeImmutable)->modify('+1 day')->format('U');
return $day;
}
}
As you can see in oneDayStartingToday, the static method can access private fields of the instance! Crazy isn't it ? :)
For a better explanation, see http://verraes.net/2014/06/named-constructors-in-php/
The naming of any method should be with intention revealing names. I can't tell what 'Foo::factory' does. Try to build to a higher level language:
User::with100StartingPoints();
This would be the same as:
$user = new User();
$user->setPointsTo(100);
You could also easily test whether User::with100StartingPoints() is equal to this.
If you don't need a reference to the newly constructed Foo, why don't you simply make set_sth a static function (and have it create a new Foo internally if required)?
If you do need to get hold of the reference, how would you do it? return $this in set_sth? But then set_sth can be made into a factory function anyway.
The only situation I can think of is if you want to call chainable methods (like in a fluent interface) on a newly constructed instance all in one expression. Is that what you are trying to do?
Anyway, you can use a general-purpose factory function for all types of objects, e.g.
function create_new($type) {
return new $type;
}
create_new('Foo')->set_sth();
It's probably not quite a best practice, but you could use the fact that functions and classes have two different namespaces : you can have a function that have the same name as a class.
This allows one to write this kind of code, for example :
function MyClass() {
return new MyClass();
}
class MyClass {
public function __construct() {
$this->a = "plop";
}
public function test() {
echo $this->a;
}
protected $a;
}
Note that I have defined a function called MyClass, and a class with the same name.
Then, you can write this :
MyClass()->test();
Which will work perfectly, and not get you any error -- here, you'll get the following output :
plop
Addition to Jon's answer: To allow constructor arguments use the following:
function create($type) {
$args = func_get_args();
$reflect = new ReflectionClass(array_shift($args));
return $reflect->newInstanceArgs($args);
}
create('Foo', 'some', 'args')->bar();
Documentation: ReflectionClass->newInstanceArgs
These are called creation methods, and I typically name them createXXX() such as createById() or createEmptyCatalog(). Not only do they provide a nice way to reveal the different intentions of an object's constructors, but they enable immediate method chaining in a fluent interface.
echo Html_Img::createStatic('/images/missing-image.jpg')
->setSize(60, 90)
->setTitle('No image for this article')
->setClass('article-thumbnail');
Propel uses a static method "create". I'd go with that. This method makes the code easier to test rather than just using static methods to perform business logic.
<?php
class MyClass
{
public static function create()
{
return new MyClass();
}
public function myMethod()
{
}
}
Besides, you can also pass parameters to the constructor. For instance:
<?php
class MyClass
{
public function __construct($param1, $param2)
{
//initialization using params
}
public static function create($param1, $param2)
{
return new MyClass($param1, $param2); // return new self($param1, $param2); alternative ;)
}
public function myMethod()
{
}
}
In either case, you'd be able to invoke myMethod right after the create method
<?php
MyClass::create()->myMethod();
// or
MyClass::create($param1, $param2)->myMethod();
A bit late to the party but I think this might help.
class MyClass
{
function __construct() {
// constructor initializations here
}
public static myMethod($set = null) {
// if myclass is not instantiated
if (is_null($set)) {
// return new instance
$d = new MyClass();
return $d->Up('s');
} else {
// myclass is instantiated
// my method code goes here
}
}
}
this can then be used as
$result = MyClass::myMethod();
optional parameters can be passed through either the __constructor or myMethod.
This is my first post and I hope I got the gimmicks right

PHP: 'Dynamic' callback from inside/outside a class

we have a problem [cit.]
I need to assign a callback dynamically within a class, in base of a variable param: my goal is to have just one class (and not a main class and many extender sub-class), and inside this class if a value is X, then the funcitonX must be used, if is Y, the functionY.
I know i cant explain well, i hope my example will do:
class plzComplicateMyLife{
public $vehicle;
public $kindVehicle;
public $dynamicFunction;
public function __construct($vehicle, $kindVehicle){
$this->kindVehicle = $kindVehicle;
$this->vehicle = $vehicle;
switch($kindVehicle){
case 'cycle':
$this->dynamicFunction = "isACycle";
break;
case 'car':
$this->dynamicFunction = "isACar";
break;
}
//here come the problem, i need to call the callback store in dynamicFunction.
//i tried:
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//error: Catchable fatal error: Object of class plzComplicateMyLife could not be converted to string in [...]
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//Warning: call_user_func(plzComplicateMyLife::isACar) [function.call-user-func]: First argument is expected to be a valid callback in [...]
//$this->dynamicFunction();
//Fatal error: Call to undefined method plzComplicateMyLife::dynamicFunction() in [...]
//so, how can i do that?
}
public function isACycle($vehicle){
echo 'im a cycle, model: '.$vehicle.'<br />';
}
public function isACar($vehicle){
echo 'im a car, model: '.$vehicle.'<br />';
}
//i know this has no sense, in this example at least.
public function printKind(){
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//then?
}
}
$maserati = new plzComplicateMyLife('maserati4', 'car');
//then, maybe, outside the class i'll need to recover the callback:
$maserati->printKind();
EDIT:
As Rob said, polymorphism would be really a good solution.
But the problem is that, in this case, i really must have the same declaration for every class instance, changing only the parameters...e.g:
$maserati = new plzComplicateMyLife('maserati4', 'car');
$ducati = new plzComplicateMyLife('maserati4', 'cycle');
//is good
//becose i cant have:
$maserati = new plzComplicateMyLifeWithACar('maserati4');
$ducati = new plzComplicateMyLifeWithACycle('maserati4');
Polymorphism is the way to go here but for future reference you can also do this:
public function printKind() {
$this->{$this->dynamicFunction}($this->vehicle);
}
In response to your edit, could you not do something like this instead?
abstract class MethodOfTransport {
protected $model;
public function __construct($model) {
$this->model = $model;
}
abstract public function printKind();
public static function create($model, $type) {
$object = new $type($model);
return $object;
}
}
class cycle extends MethodOfTransport {
public function printKind() {
echo 'im a cycle, model: '.$this->model.'<br />';
}
}
class car extends MethodOfTransport {
public function printKind() {
echo 'im a car, model: '.$this->model.'<br />';
}
}
$maserati = MethodOfTransport::create('maserati4', 'car');
$maserati->printKind();
$ducati = MethodOfTransport::create('maserati4', 'cycle');
$ducati->printKind();
In PHP you can use specify a method callback using an array as a callback variable (see here), for example:
array( $object, $methodName );
So you could do this
$callback = array($this, $this->dynamicFunction);
call_user_func($callback, $this->vehicle);
Er, why don't you want to use a simple inheritance structure here? If you want different behaviour depending upon the object modelled, then that's pretty much the canonical description of polymorphism.
If you really do want to plough on with callbacks into the same object, then you'll need to do one of two things:
Drop the $vehicle parameter from your callbacks, make them private or protected, and call into them normally, i.e.
call_user_func( array( $this, 'isACycle' ) );
Mark the callback as static, make them private or protected, and call into them as follows:
call_user_func( array( __CLASS__, 'isACycle' ), $this );
Within the non-static callback, access the object's properties via $this in the normal fashion. Note also that I suggest marking the callback as private or protected, in order to prevent unnecessary outside callers; presumably, you don't want them executing the wrong method for each type.

Redefine Class Methods or Class

Is there any way to redefine a class or some of its methods without using typical inheritance? For example:
class third_party_library {
function buggy_function() {
return 'bad result';
}
function other_functions(){
return 'blah';
}
}
What can I do to replace buggy_function()? Obviously this is what I would like to do
class third_party_library redefines third_party_library{
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
This is my exact dilemma: I updated a third party library that breaks my code. I don't want to modify the library directly, as future updates could break the code again. I'm looking for a seamless way to replace the class method.
I've found this library that says it can do it, but I'm wary as it's 4 years old.
EDIT:
I should have clarified that I cannot rename the class from third_party_library to magical_third_party_library or anything else because of framework limitations.
For my purposes, would it be possible to just add a function to the class? I think you can do this in C# with something called a "partial class."
It's called monkey patching. But, PHP doesn't have native support for it.
Though, as others have also pointed out, the runkit library is available for adding support to the language and is the successor to classkit. And, though it seemed to have been abandoned by its creator (having stated that it wasn't compatible with PHP 5.2 and later), the project does now appear to have a new home and maintainer.
I still can't say I'm a fan of its approach. Making modifications by evaluating strings of code has always seemed to me to be potentially hazardous and difficult to debug.
Still, runkit_method_redefine appears to be what you're looking for, and an example of its use can be found in /tests/runkit_method_redefine.phpt in the repository:
runkit_method_redefine('third_party_library', 'buggy_function', '',
'return \'good result\''
);
runkit seems like a good solution but its not enabled by default and parts of it are still experimental. So I hacked together a small class which replaces function definitions in a class file. Example usage:
class Patch {
private $_code;
public function __construct($include_file = null) {
if ( $include_file ) {
$this->includeCode($include_file);
}
}
public function setCode($code) {
$this->_code = $code;
}
public function includeCode($path) {
$fp = fopen($path,'r');
$contents = fread($fp, filesize($path));
$contents = str_replace('<?php','',$contents);
$contents = str_replace('?>','',$contents);
fclose($fp);
$this->setCode($contents);
}
function redefineFunction($new_function) {
preg_match('/function (.+)\(/', $new_function, $aryMatches);
$func_name = trim($aryMatches[1]);
if ( preg_match('/((private|protected|public) function '.$func_name.'[\w\W\n]+?)(private|protected|public)/s', $this->_code, $aryMatches) ) {
$search_code = $aryMatches[1];
$new_code = str_replace($search_code, $new_function."\n\n", $this->_code);
$this->setCode($new_code);
return true;
} else {
return false;
}
}
function getCode() {
return $this->_code;
}
}
Then include the class to be modified and redefine its methods:
$objPatch = new Patch('path_to_class_file.php');
$objPatch->redefineFunction("
protected function foo(\$arg1, \$arg2)
{
return \$arg1+\$arg2;
}");
Then eval the new code:
eval($objPatch->getCode());
A little crude but it works!
For people that are still looking for this answer.
You should use extends in combination with namespaces.
like this:
namespace MyCustomName;
class third_party_library extends \third_party_library {
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
Then to use it do like this:
use MyCustomName\third_party_library;
$test = new third_party_library();
$test->buggy_function();
//or static.
third_party_library::other_functions();
For the sake of completeness - monkey patching is available in PHP through runkit. For details, see runkit_method_redefine().
How about wrapping it in another class like
class Wrapper {
private $third_party_library;
function __construct() { $this->third_party_library = new Third_party_library(); }
function __call($method, $args) {
return call_user_func_array(array($this->third_party_library, $method), $args);
}
}
Yes, it's called extend:
<?php
class sd_third_party_library extends third_party_library
{
function buggy_function() {
return 'good result';
}
function other_functions(){
return 'blah';
}
}
I prefixed with "sd". ;-)
Keep in mind that when you extend a class to override methods, the method's signature has to match the original. So for example if the original said buggy_function($foo, $bar), it has to match the parameters in the class extending it.
PHP is pretty verbose about it.
Zend Studio and PDT (eclipse based ide) have some built in refractoring tools. But there are no built in methods to do this.
Also you wouldn't want to have bad code in your system at all. Since it could be called upon by mistake.
I've modified the code from the answer by #JPhilly and made it possible to rename a the patched class to avoid errors.
Also, I've changed the regex that identifies the about-to-be-replaced function to fit cases where the replaced function doesn't have any class access modifiers in front of its name
Hope it helps.
class Patch {
private $_code;
public function __construct($include_file = null) {
if ( $include_file ) {
$this->includeCode($include_file);
}
}
public function setCode($code) {
$this->_code = $code;
}
public function includeCode($path) {
$fp = fopen($path,'r');
$contents = fread($fp, filesize($path));
$contents = str_replace('<?php','',$contents);
$contents = str_replace('?>','',$contents);
fclose($fp);
$this->setCode($contents);
}
function redefineFunction($new_function) {
preg_match('/function ([^\(]*)\(/', $new_function, $aryMatches);
$func_name = trim($aryMatches[1]);
// capture the function with its body and replace it with the new function
if ( preg_match('/((private|protected|public)?\s?function ' . $func_name .'[\w\W\n]+?)(private|protected|public|function|class)/s', $this->_code, $aryMatches) ) {
$search_code = $aryMatches[1];
$new_code = str_replace($search_code, $new_function."\n\n", $this->_code);
$this->setCode($new_code);
return true;
} else {
return false;
}
}
function renameClass($old_name, $new_name) {
$new_code = str_replace("class $old_name ", "class $new_name ", $this->_code);
$this->setCode($new_code);
}
function getCode() {
return $this->_code;
}
}
This is how I've used it to patch a Wordpress plugin:
$objPatch = new Patch(ABSPATH . 'wp-content/plugins/a-plugin/code.php');
$objPatch->renameClass("Patched_AClass", "Patched_Patched_AClass"); // just to avoid class redefinition
$objPatch->redefineFunction("
function default_initialize() {
echo 'my patched function';
}");
eval($objPatch->getCode());
$result = new Patched_AClass();
If the library is explicitly creating the bad class and not using a locater or dependency system you are out of luck. There is no way to override a method on another class unless you subclass.
The solution might be to create a patch file that fixes the library, so you can upgrade the library and re-apply the patch to fix that specific method.
You might be able to do this with runkit. http://php.net/runkit
You can make a copy of the library class, with everything the same except the class name. Then override that renamed class.
It's not perfect, but it does improve the visibility of the extending class's changes. If you fetch the library with something like Composer, you'll have to commit the copy to source control and update it when you update the library.
In my case it was an old version of https://github.com/bshaffer/oauth2-server-php. I modified the library's autoloader to fetch my class file instead. My class file took on the original name and extended a copied version of one of the files.
Since you always have access to the base code in PHP, redefine the main class functions you want to override as follows, this should leave your interfaces intact:
class third_party_library {
public static $buggy_function;
public static $ranOnce=false;
public function __construct(){
if(!self::$ranOnce){
self::$buggy_function = function(){ return 'bad result'; };
self::$ranOnce=true;
}
.
.
.
}
function buggy_function() {
return self::$buggy_function();
}
}
You may for some reason use a private variable but then you will only be able to access the function by extending the class or logic inside the class. Similarly it's possible you'd want to have different objects of the same class have different functions. If so, do't use static, but usually you want it to be static so you don't duplicate the memory use for each object made. The 'ranOnce' code just makes sure you only need to initialize it once for the class, not for every $myObject = new third_party_library()
Now, later on in your code or another class - whenever the logic hits a point where you need to override the function - simply do as follows:
$backup['buggy_function'] = third_party_library::$buggy_function;
third_party_library::$buggy_function = function(){
//do stuff
return $great_calculation;
}
.
.
. //do other stuff that needs the override
. //when finished, restore the original function
.
third_party_library::$buggy_function=$backup['buggy_function'];
As a side note, if you do all your class functions this way and use a string-based key/value store like public static $functions['function_name'] = function(...){...}; this can be useful for reflection. Not as much in PHP as other languages though because you can already grab the class and function names, but you can save some processing and future users of your class can use overrides in PHP. It is however, one extra level of indirection, so I would avoid using it on primitive classes wherever possible.
There's alway extending the class with a new, proper, method and calling that class instead of the buggy one.
class my_better_class Extends some_buggy_class {
function non_buggy_function() {
return 'good result';
}
}
(Sorry for the crappy formatting)

Categories