I'm attempting to create a Trait to make "freezable value objects". (To avoid positional parameters and telescoping constructors.) This means the setters can be used to initialize the object, and then ->freeze() is called, which makes the object "immutable". The setters will still be there, but when called, they will throw an exception. This can be achieved with a $this->assertIsWritable(); call at the start of each setter. However I'd like to avoid this (as its easy to forget such a call) and do this check automatically. Is there a way to intercept calls to defined methods?
Not acceptable in the solution:
Approaches that break type hinting and/or static code analysis
Dependence on special PHP extensions
I'm using PHP 7.0.
This is not possible without modifying the runtime (using extensions such as Runkit or uopz or performing source code transformation on your PHP code while it being loaded (using stream wrapper magic).
Related
I've started a new project recently and decided to have some functions under their own namespace (e.g general functional programming functions).
I've created a test and included the annotation but now I'm getting the following warning when testing for coverage:
"#covers ::pipe" is invalid
If I use \Example\FP\pipe the warning goes away but surely that's incorrect as there's nothing indicating it's a function (there's no class either in this case).
I've searched online, even considered raising an issue because as far as I can tell you either have a global function and use #covers ::functionName -or- you're forced to make it a static method.
A few questions:
Is there a known solution when having namespaced functions that I'm just simply missing?
Is the norm to just use static methods? If yes, why is it better than standard functions?
Not needed: Is there a (significant) performance penalty of using static methods over normal functions?
Later edit:
3 - found Performance of static methods vs. functions
I'm trying to build a tool that add/remove methods for me in a class, basically saving me the time to type some standard methods I use in my framework.
However, it seems to me that the getMethods method of the ReflectionClass uses some sort of cache, because if I call getMethods once, then change the methods dynamically (for instance replacing the class file with another one with the same class name but different methods), then call getMethods again, it doesn't take into account my dynamic changes.
I tried sleep, but it was obviously not that.
I was wondering if there is a way (but I'm afraid there is not) in php to "refresh" the ReflectionClass, so that it can "reflect" on the actual content rather than on some sort of cache.
As a work around, I can rely on tokens, but that requires a bit more work than just using the Reflection classes, so it would be great if I could "reset" the Reflection cache somehow.
With the constraints you have I dont see a way to do this natively.
Maybe you can consider using runkit https://www.php.net/manual/en/function.runkit-method-redefine.php because it would seem to be possible (and maybe it will suit your needs) but I'll stick to base PHP in my answer.
You never use reflection on a file, you use reflection on a class/function, etc. so on code level. And to use reflection on a class you have to declare it first (require, autoload, etc.) and once it is declared thats it, you cannot redeclare it. Trying to require file with the same class will result in an error.
So requiring a file with a class, using the class and then changing the file itself will have no effect. Take a look at the code:
<?php
file_put_contents('a.php', '<?php class A {function a() {return "a";}}');
require('a.php');
$a = new A();
var_dump($a->a());
file_put_contents('a.php', '<?php class A {function b() {return "b";}}');
$a = new A();
var_dump($a->b());
Not even mentioning reflection at this point - how would you make this code print 'b'? You will get PHP Fatal error: Uncaught Error: Call to undefined method A::b() in ... because defined version is still the one you required. Requiring file again will result in PHP Fatal error: Cannot declare class A, because the name is already in use in ....
So I think reflection is working correctly.
coming from Java, I only have a few vacational visits to PHP. Looking at magic get and set methods, my (Java influenced) tummy starts hurting: It looks as if you were accessing properties directly (although, of course, you are actually are using __get and __set).
So - except for less code you have to write, are there any advantages to using magic getter and setter methods instead of traditional getX()/setX() methods? Should I start using them when coding PHP?
Thanks and best!
The only benefit of __get() is the possibility of less code, but even then it's not necessarily the case. For example, if you have a set of 10 private members and you want the getter to reveal 5, you have to write __get() so that if one of the psuedo-visible members is called, you send it. Otherwise, you either issue an error (that would otherwise come naturally without __get() or return a value such as null that may not actually be helpful.
I must excoriate anyone who suggests using getters and setters in general at all. This usually indicates a problem with architecture. Explain the conceptual difference between the two following code blocks, for instance:
class _ {
public $_;
}
vs.
class _ {
private $_;
public function get_() {
return $this->_;
}
}
There isn't a difference.
However, as many will point out the advantage of having a getter is that this allows you to modify the return value in some way transparently to make it useful for the recipient. However, we come back to architecture problems. You should never have to expose the contents of a class for any reason at all. Instead, you should tell the class to perform an action (which may vary based on its state). Using getters generally lends to querying the class' state and performing an action externally based on the viewed state.
I have essentially the same arguments against __set() and setters, but there is one nice thing that __set() lets you do:
class _ {
private $_ = array();
public function __set($key, $val) {
$this->_[$key] = $val;
}
}
This lets you type the very nice $_obj->key = 'val'. Note that there is not much difference from this and adding another method such as add() that takes the key and value and does the same thing, I just prefer the object setter notation.
__get__ and __set__ are fully dynamic. So for example you can start a database request if they are called to enable lazy loading. Of course, you could do this with getters and setters, too, but then you would have to do this every time. You can also do something like AOP because every property call gets passed through one single method. So all in all __get__/__set__ offer more flexilibility against time they take to process. You can do really advanced/cool stuff with it.
The advantages are that when you're refactoring, direct assignments / reads can be handled without the need to immediately change the complete codebase too, the code can be somewhat shorter, and people can create strings somewhat more easily (for example: $title="<title>{$obj->title}</title>"; vs. $title='<title>'.$obj->getTitle().'</title>';.
However, __get & __set methods can become large and unwieldy fairly quickly, and when coding properly & explicitly, it is in my opinion better to use explicit set/getX() methods to make clear functions are called, and the minor increase of code verbosity is as far as I'm concerned justified as one can easily see what actually calls a function and what doesn't. A possible exception could be when you are building a decorator for another class/object, but that's about it.
there is few difference between getter and setter methods and __set() and __get() methods! these are magic methods!
__set() use when you wanna assign undefined state to a object and so __get() also use to fetch value of undefined state!
setter and getter are used to assign or fetch value of defined states
except for less code you have to write, are there any advantages to using magic getter and setter >methods instead of traditional getX()/setX() methods? Should I start using them when coding PHP?
Given that less code to write it's already a strong reason to start use them.
the other reason is that you can add a common behaviour to all your getter/setter
function __set() {
//> Do some code in common between all setter
//> set your var here
}
When writing getX()/setX() for each attribute, practically speaking, you'll have at a minimum, 7 lines of code. This is assuming that your opening method brace is on the same line as the definition and you only put a single line of code into the method, then you have your closing brace on its own line.
For a non-trivial object, multiply that by 6 (YMMV). That is 42 lines just for attribute access/mutation. That does not include input validation or normalization. For an alternative, check out: https://github.com/metaphp/attributes
There are overheads in dynamic programming (e.g. using magic methods). An old benchmark: Benchmarking magic
As PHP is a dynamic (and not a completely enterprise) language, reducing code lines and missing some nanoseconds seems good idea in many cases (for debugging, scalability, reducing errors and etc).
I have some very test-unfriendly code (to say the least) that I need to test. Refactoring unfortunately is not an option. I have to test the code as it is, without the possibility of changing it.
To do that, I was thinking of intercepting function calls and dynamically change what they do so I can run my tests, as I need some functions and methods to return known values, and I need others that make requests, connect to the database, etc, to stop doing that and return what I need them to return. Is there any way to do this without runkit_method_redefine(), which is preferably not "EXPERIMENTAL" and still maintained? Maybe an alternative to runkit? Maybe a better way?
Edit: will use PHPUnit's test doubles and PHP 5.3.2's features for making private methods accessible, if I need that functionality.
Note: the Test-Helper extension is superseded by https://github.com/krakjoe/uopz
PHPUnit's Test Helper extension (PECL) allows redefiniton/intercepting/stubbing/mocking of hardcoded dependencies with your own implementations:
protected function setUp()
{
$this->getMock(
'Bar', /* name of class to mock */
array('doSomethingElse'), /* list of methods to mock */
array(), /* constructor arguments */
'BarMock' /* name for mocked class */
);
set_new_overload(array($this, 'newCallback'));
}
It also allows intercepting the exit statement and instance creation:
https://github.com/sebastianbergmann/php-test-helpers
For stubbing and mocking methods you simply use PHPUnit's regular mocking framework. See
http://www.phpunit.de/manual/current/en/test-doubles.html
You can also use Mockery with PHPUnit:
https://github.com/padraic/mockery
Another option would be to use http://antecedent.github.io/patchwork
Patchwork is a PHP library that makes it possible to redefine user-defined functions and methods at runtime, loosely replicating the functionality runkit_function_redefine in pure PHP 5.3 code, which, among other things, enables you to replace static and private methods with test doubles.
The runkit extension is a perfect solution for your needs. It is proven by years of my personal experience and described in many presentations and articles authored by different authors in the internet.
I can assure you that the runkit_method_redefine function as well as the whole runkit extension is not experimental anymore (documentation hosted on the php.net is obsolete).
The up-to-date runkit extension can be found on http://github.com/zenovich/runkit
Sincerely,
Dmitry Zenovich
A little background: At runtime I would like to be able to inspect the currently called functions javadoc-style documentation, to determine its formal (typed) declaration. This would allow runtime type checking (for simple and complex types) by means of reflection (at a cost) during debugging and testing, something that I would find immensely helpful.
So, in php I would like for a user defined function to get called whenever any other function is about to get called. That is, if a function foo() gets called, I would like to have my callHookHandler() function called immediately before.
One solution would be to implement __call() in all user defined classes, but that is both unwieldy and doesn't include support for functions defined outside classes, so I am looking for a better solution.
This sounds a bit of a fun one so I'm going to give answering it a try.
I hope this helps you. Let me know how it goes.
So, what you are asking can be done, and here's how:
For Functions:
Get all defined functions with $function = get_defined_functions().
Loop through the $functions['user'] key and inspect each one with the ReflectionFunction class. You'll need to get:
The comment using ->getDocComment()
The arguments using ->getParameters()
Do some magic (I'll let you figure out how to parse the comment using some regular extressions and match it up with the parameter list from the reflection. Don't forget optional parameters!)
Rename the function using runkit_function_rename
Generate code in a string that checks the parameters and calls the renamed function
Generate a parameter list as a string
Create a new function with runkit_function_add using the code you generated in step #5 and the parameter list from step #6.
For Classes:
Get a list of classes with $classes = get_declared_classes();
Loop through each one and inspect it with ReflectionObject and ->getMethods() to get the methods. Make sure that the class is not internal with ->isInternal() because we can't do anything about the internal classes.
In an inner loop... go through each method using the ReflectionMethod class. Get the arguments and PHPDoc/JavaDoc comments just like you did with normal functions.
Do the same thing you did with the functions only use runkit_method_add and runkit_method_rename instead.
Downsides:
You won't be able to do the checking on internal class methods and functions (which is fine because they won't have doc comments anyway).
This is a lot of work! I left a lot of parts up to your imagination to avoid this being the length of a short book.
Please send me this or open source it and let me know when you finish, I really want to use this myself. Contact info is on my website which is in my profile ;)
Alternatively:
You can use XDebug's function trace along with reflection then analyze the results after the fact so that you don't have to dynamically edit the code. If you want to write unit-test you could even automate it.
Hope type checking makes it into future versions of PHP and wait: https://wiki.php.net/rfc/typechecking
Notes:
This class reference has a potentially useful example of parsing docComments in the comments section of the page:
http://us.php.net/manual/en/class.reflectionmethod.php
References
get_defined_functions
get_declared_classes
ReflectionFunction
ReflectionObject
ReflectionMethod
runkit
Alternative way to hook into function call is to use a trick with namespaces: Intercepting Execution of System Functions in PHP
You can also use the Go! framework to define an aspect to intercept the execution of system functions automatically.