How to detect dynamic declarated fields on objects with codesniffer in PHP - php

After a refactoring, we had something like this in one of our classes:
class FooBar
{
// $foo was $bla before
private $foo;
public function setBlubbOnArrayOnlyOnce($value)
{
// $this->bla was forgotten during refactoring. Must be $this->foo
if(!isset($this->bla['blubb'])) {
$this->foo['blubb'] = $value;
}
}
}
So in the end $this->foo['blubb'] was always set, not only once.
This happens because of the magic methods of PHP. We don't want it to be possible to access fields dynamically, so I thought I just add a codesniffer rule. But I didn't found any and asked me why.
PHPStorm shows a field declared dynamically notice there, but I want this to automatically fail with codesniffer (or something similar) during our deployment cycle.
Has anybody an idea on this? Is there a good rule? Should I write my own and how? Or would it be bad practice to disable it?
Disclaimer: We use tests, but sometimes you miss things... It would be good to prevent this in the first place. Also, please don't come up with overwriting the magic methods. I don't want to have a trait/abstract whatever in every class.

This is not a codesniffer or phpstorm problem. And you cant want fix this problem with codesniffer or IDE. IDE, codesniffer, phpdocumentor, etc. -- this is "statically" analyse. And for dynamic analyse you can use e.g. phpunit.
If you want check existence of property you must use property_exists() function.
class X
{
public function __get($name)
{
$this->{$name} = null;
return $this->{$name};
}
}
$x = new X();
var_dump(property_exists($x, 'foo')); // false
var_dump($x->foo); // NULL
var_dump(property_exists($x, 'foo')); // true
Or may be you can use reflection for property http://php.net/manual/en/class.reflectionproperty.php
If you want check for "isset" you must known:
var_dump(isset($x), $x); // false + NULL with notice
$x = null;
var_dump(isset($x), $x); // false + NULL
unset($x);
var_dump(isset($x), $x); // false + NULL without notice
When you shure for this case of check you can use isset()
But you should always first check for existence of property. Otherwise you can have undefined behaviour of your code.

After a refactoring
It would be good to prevent this in the first place.
You can only catch these kind of refactoring errors by running tests after each refactoring step. This error will also bubble up, because foo['blubb'] is set to a specific value and this should cause an unwanted effect in another test - not only in the test for the setter logic.
We use tests, but sometimes you miss things...
Yes, its quite common that the coverage is not high enough.
That's why having a good test coverage is the starting point for all refactorings.
These two lines were not "green" in your coverage report:
if(!isset($this->bla['blubb'])) {
$this->foo['blubb'] = $value;
Also, please don't come up with overwriting the magic methods. I don't want to have a trait/abstract whatever in every class.
You have excluded it, but that's one way to catch the properties: by using the magic function __set() (for inaccessible vars) or property_exists() or the use of Reflection* classes to find.
Now, that its too late, you want another tool to catch the error, ok:
The tool would need to parse the PHP file and its parents (because of variable scope) and find $this->bla without a prior public|private|protected variable (class property) declaration. This will not indicate the exact type of error, just that "bla" was accessed without declaration.
Its possible to implement this as a CodeSniffer rule.
You can also give http://phpmd.org/ or https://scrutinizer-ci.com/ a try.
And, in case you are using PHP7: https://github.com/etsy/phan
tl;tr
Its complicated to determine the exact error and its context without running, evaluating and analyzing the underlying code. Just think about "dynamic variable names" and you know why: you don't even know the name of the property by looking at the source-code, because its build dynamically during program flow. A static analyzer wouldn't catch that.
A dynamical analyzer has to track all things, here $this-> accesses and would take the context into account: !isset(x). Context evaluation can find lots of common coding mistakes. In the end you can build a report: saying that $this->bla was accessed only 1 time and that indicates either that
a dynamically declared property was introduced, but never re-used, with the suggestion that you might drop it or declare it as class property
OR with added context evaluation: that and when this variable was accessed from inside a isset() - that a non-existing key of a non-declared property was accessed, without a prior set(), etc.

Now in 2017, you'are looking for tool PHPStan. I link short intro I wrote for first time users.
It does exactly what you need!

Related

How to deal with "method not found in class" warning for magically implemented methods?

I am sitting on a large codebase that contains several classes that expose functionality through magically implemented methods (using __call and __callStatic). For example:
class Foo {
public function __call($name, $parameters) {
echo "You called $name().\n";
}
}
$f = new Foo;
$f->test(); // runs fine, but PhpStorm flags as a warning
The problem is that PhpStorm thinks that the test() method does not exist, so it gives a warning at the call site. This is a little annoying, as of course the code will run and behave as expected.
I have already tuned down the severity by checking the "downgrade severity if __magic methods are present in class" option, but I would prefer to either:
completely disable this functionality for specific classes only, or
work with the IDE rather than against it -- provide it with the information I already have so our views agree
Is any of the above possible? If so, how?
Additional bonus question: consider the case where method calls are being chained.
$f = new Foo;
$f->test()->chain()->moreChain(); // potentially runs fine
Assuming that the magic call to $f->test() returns something appropriate the subsequent (possibly, but not necessarily, also magic) calls will work fine. However, since there is no way that I know of to tell the IDE what test() returns it flags the rest of the call chain as full of missing methods too. And to make matters worse, the "downgrade severity" setting does not apply to these warnings since the IDE does not know what class these intermediate objects are supposed to be.
Is there a solution that can also cover this case?
Update
Even though documenting the magic methods with #method annotations seems to work, I have to assume that there are currently several problems with this approach because it only took me a little work to come upon these related bugs:
Type hinting for the method arguments does not work correctly with primitives
Annotations work for one call, but not for chained calls
I do hope they fix them in a reasonable time frame.
Well, you can go to the preference menu, under Inspections, go to Undefined -> Undefined Method and check Downgrade severity if __magic methods are present.
That would make the flag less severe, (instead of Warning, as Info), which would still give you a green light on your document check.
There's nothing else I'm aware of aside from having #property or #method PHPDoc notations on the target class for every method that's likely to be used.
Rather than globally turning off inspections by downgrading the severity of the inspection, you can add a comment to the single line to ignore just that particular inspection.
/** #noinspection PhpUndefinedMethodInspection */
Assertion::NullOrAssertionDoesNotExist();
Building on what Madara said, I found it wouldn't downgrade down far enough for my liking no matter what severity I set it to, so I made a new Severity for undefined method that has no attributes whatsoever, and turned off the downgrade checkbox (see image below)
If I hover over my magic methods now, it still brings up the popup message, but otherwise it doesn't distract me. One step better than just turning off inspection, because at least this way an actual undefined method can still be detected by hovering over the name
You can use a dynamic variable :
$test = 'test';
$chaine = $f->$test(); // no phpStorm flag, & the code works

Are there advantages to using __get/__set instead of traditional getter/setter methods except for less code?

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).

Independent getter/setter methods, or combined?

While working on a project, I've been making some changes and browsing around existing framework API docs for insight.
While perusing the Kohana docs, I noticed that the getters/setters of any given class are typically combined:
public function someProperty($value = null){
if(is_null($value){
return $this->_someProperty;
}
$this->_someProperty = $value;
return $this;
}
Rather than:
public function setSomeProperty($value){
$this->_someProperty = $value;
return $this;
}
public function getSomeProperty(){
return $this->_someProperty;
}
Is there any value in doing this (the former), beyond lessening the method count of a given class? I was always under the understanding that methods (functions in general) should be more descriptive of an action. Do other experienced developers cringe, even a tiny bit, when they see this?
I was just surprised to see a popular framework use such conventions (I haven't used Kohana of course)
I consider this bad practise because it violates CommandQuerySeparation. Setting a value is changing state (Command). Getting a value is asking for state (Query). A method should not do both, but one thing only.
Also, it's not really obvious what a method does when it's just called username, e.g. does not have a verb, like get or set. This gets even worse in your example, because the return value is either the object itself or the property value, so its not consistent.
Moreover, getters (and setters) should be used sparingly as they will quickly convolute your API. The more getters and setters you have, the more knowledge about an object is required by collaborators of that object. If you find your objects asking other objects about their internals, chances are you misplaced the responsibilities.
jQuery goes the same way as Kohana. However I think it's better to create separate methods for setting and getting. It's more obvious what the method does and I think it's more practically in code-completition in your ide. For example you type set and you get a list of all Properties you can set.
Another disadvantage is: what if you want to set a value really to null? This wouldn't work since the null is the identifier for returnin the value, you are restricted in setting specific values...
So it's nice, since you'll have to write less, but hey what are three letters (set/get) in front of your methods?
Despite the fact that Kohana uses such unusual technique for the OOP, I think you should follow coding conventions at first. But of course it's better to use separate getters and setters for every property in your classes. So, if it's possible to use them not breaking the conventions - just do it and you won't be wrong ;) . You can also read here about good habits in PHP OOP - http://www.ibm.com/developerworks/opensource/library/os-php-7oohabits/ if you've doubted about using some OOP technics. Hope that it'll help :)
I'd rather believe they had a reasonable explanation for doing it this way. For example, for easier implementation of ArrayAccess. Only way to know for sure is to ask them directly.
To answer your question, yes I cringe when I see the first method. Goes against OOP principles.
Why not do it like this?
public function someProperty($value = null)
{
if (func_num_args() === 1) {
$this->someProperty = $value;
return $this;
} else {
return $this->someProperty;
}
}
This would imo be the only correct way to implement a combined getter/setter
If you do it everywhere it is a good way, but than it really needs to be for everything, maybe the programmers of this framework are used to is, (it's a bit jquery alike)
However it would confuse me
For setting and getting I always use setters and getters:
public function __set($key, $value) {
// assign value $value to $this->key
}
public function __get($key) {
// return value of this->key
}
For the sake of argument,
The combined approach does offer some benefits:
Avoids __get and __set magic while still emulating a public property. (I would not ever recommend using magic for these situations anyway)
Using thing() is less verbose than using getThing() setThing().
Even though the methods will be doing more, they can still be considered as "doing one thing()", that is handling the thing(). Properties also do more than one thing. They allow you to set and get values.
It's argued that the thing() doesn't give a verb. However, we can assume that a thing() without a verb means that we use it like a property (we get and set it). For interfaces, we can say that a thing() with no argument is readonly and a thing($arg) with an argument is read/write. Why should we be shy from adopting this? At some point we adopted the idea of adding getters and setters didn't we?
If you are using a web-based language (like PHP), then chances are you might be using jQuery as well. JQuery is already doing this sort of thing() and it has worked out well.
Using func_num_args(), as mentioned already, helps achieve this approach perfectly.
Personally, I've already taken a good portion of risks in my current apps at this point so I'm probably going with the old tried-and-true getters and setters (see the section "Finding the Balance" of Jimmy Bogard's post in regards to getters/setters for data operations). And I suppose we are already trained to look for these get/set prefixes (as well as our IDE's) to see what properties we can work with in a class. This is a discussion I would be open to returning to at some point.

assert dilemma in unit testing class

I would like to use PHP's assert function in my unit testing framework. It has the advantage of being able to see the expression being evaluated (including comments) within the error message.
The problem is that each method containing tests may have more than one assert statement, and I would like to keep track of how many actual assert statements have been run. assert does not give me a way to count how many times it has been run, only how many times it has failed (within the failure callback).
I tried to abstract the assert statement into a function so that I can add a counting mechanism.
private function assertTrue($expression) {
$this->testCount++;
assert($expression);
}
This does not work however because any variables within the expression are now out of scope.
$var = true;
$this->assertTrue('$var == true'); // fails
Any advice on how I can use assert in my unit testing while being able to count the number of actual tests?
The two ideas I have come up with are to make users count themselves
$this->testCount++;
assert('$foo');
$this->testCount++;
assert('$bar');
or make users put only one assert in each test method (I could then count the number of methods run). but neither of these solutions is very enforcable, and make coding more difficult. Any ideas on how to accomplish this? Or should I just strip assert() from my testing framework?
In PHPUnit, all of the assert*() methods take an additional $message parameter, which you can take advantage of:
$this->assertTrue($var, 'Expected $var to be true.');
If the assertion fails, the message is output with the failure in the post-test report.
This is more useful generally than outputting the actual expression because then you can comment on the significance of the failure:
$this->assertTrue($var, 'Expected result of x to be true when y and z.');
A bit of a cheeky answer here, but open vim and type:
:%s/assert(\(.+\));/assert(\1) ? $assertSuccesses++ : $assertFailures++;/g
(In principle, replace all assert() calls with assert() ? $success++ : $fail++;)
More seriously, providing a mechanism to count tests is really a responsibility a bit beyond the scope of the assert() function. Presumably you want this for an "X/Y tests succeeded" type indicator. You should be doing this in a testing framework, recording what each test is, its outcome and any other debug information.
You are restricted by the fact assert() must be called in the same scope the variables you are testing lie. That leaves -- as far as I can tell -- solutions that require extra code, modify the source before runtime (preprocessing), or a solution that extends PHP at the C-level. This is my proposed solution that involves extra code.
class UnitTest {
// controller that runs the tests
public function runTests() {
// the unit test is called, creating a new variable holder
// and passing it to the unit test.
$this->testAbc($this->newVarScope());
}
// keeps an active reference to the variable holder
private $var_scope;
// refreshes and returns the variable holder
private function newVarScope() {
$this->var_scope = new stdClass;
return $this->var_scope;
}
// number of times $this->assert was called
public $assert_count = 0;
// our assert wrapper
private function assert($__expr) {
++$this->assert_count;
extract(get_object_vars($this->var_scope));
assert($__expr);
}
// an example unit test
private function testAbc($v) {
$v->foo = true;
$this->assert('$foo == true');
}
}
Downfalls to this approach: all variables used in unit testing must be declared as $v->* rather than $*, whereas variables written in the assert statement are still written as $*. Secondly, the warning emitted by assert() will not report the line number at which $this->assert() was called.
For more consistency you could move the assert() method to the variable holder class, as that way you could think about each unit test operating on a test bed, rather than having some sort of magical assert call.
That's not something which unit-testing is intended to do (remember it originated in compiled langs).
And PHPs semantics do not help much with what you are trying to do either.
But you could accomplish it with some syntactic overhead still:
assert('$what == "ever"') and $your->assertCount();
Or even:
$this->assertCount(assert('...'));
To get the assertion string for succeeded conditions still, you could only utilize debug_backtrace and some heuristic string extraction.
This is not enforced much either (short of running a precompiler/regex over the test scripts). But I would look at this from the upside: not every check might be significant enough to warrant recording. A wrapper method thus allows opting out.
It's hard to give an answer without knowing how your framework has been built, but I'll give it a shot.
Instead of directly call the methods of your unit testing class ( methods like assertTrue() ), you could use the magic method of PHP __call(). Using this, you could increase an internal counter everytime assertTrue() method is called. Actually, you can do whatever you want, every time any method is called.
Remember that __call() is invoked if you try to call a method that does not exist. So you would've to change all your methods names, and call them internally from __call(). For instance, you'd have a method called fAssertTrue(), but the unit testing class would use assertTrue(). So since assertTrue() is not defined, __call() method would be invoked, and there you would call fAssertTrue().
Since you're passing the expression already (which might lead, correct me if I'm wrong, to quoting hell):
$this->assertTrue('$var == true'); // fails with asset($expression);
Why not add a tiny extra layer of complexity, and avoid the quoting hell, by using a closure instead?
$this->assertTrue(function() use ($var) {
return $var == true;
}); // succeeds with asset($expression());
Simple:
$this->assertTrue($var == true);
(without quotes!)
It will be evaluated in caller space, so assertTrue() will be passed just false or true.
As others have pointed out, this might not be the best way of testing, but that's another question entirely... ;)

How do I prevent using the incorrect type in PHP?

PHP, as we all know is very loosely typed. The language does not require you to specify any kind of type for function parameters or class variables. This can be a powerful feature.
Sometimes though, it can make debugging your script a painful experience. For example, passing one kind of object into a method that expects a different kind of object can produce error messages complaining that a certain variable/method doesn't exist for the passed object. These situations are mostly annoyances. More onerous problems are when you initialize one object with an object of the wrong class, and that "wrong object" won't be used until later on in the script's execution. In this case you end up getting an error much later than when you passed the original argument.
Instead of complaining that what I passed doesn't have a specific method or variable, or waiting until much later in script execution for my passed in object to be used, I would much rather have an error message, at exactly where I specify an object of the wrong type, complaining about the object's type being incorrect or incompatible.
How do you handle these situations in your code? How do you detect incompatible types? How can I introduce some type-checking into my scripts so that I can get more easily understood error messages?
Also, how can you do all this while accounting for inheritance in Php? Consider:
<?php
class InterfaceClass
{
#...
}
class UsesInterfaceClass
{
function SetObject(&$obj)
{
// What do I put here to make sure that $obj either
// is of type InterfaceObject or inherits from it
}
}
?>
Then a user of this code implements the interface with their own concrete class:
<?php
class ConcreteClass extends InterfaceClass
{
}
?>
I want ConcreteClass instances, and all future, unknown user-defined objects, to also be acceptable to SetObject. How would you make this allowable in checking for the correct type?
Actually for classes you can provide type hinting in PHP (5+).
<?php
class UsesBaseClass
{
function SetObject(InterfaceObject $obj)
{
}
}
?>
This will also work correctly with inheritance as you would expect it to.
As an aside, don't put the word 'object' in your class names...
as an addition to Eran Galperin's response you can also use the type hinting to force parameters to be arrays - not just objects of a certain class.
<?php
class MyCoolClass {
public function passMeAnArray(array $array = array()) {
// do something with the array
}
}
?>
As you can see you can type hint that the ::passMeAnArray() method expects an array as well as provide a default value in case the method is called w/o any parameters.
For primitive types you could also use the is_* functions :
public function Add($a, $b)
{
if (!is_int($a) || !is_int($b))
throw new InvalidArgumentException();
return $a + $b;
}
You see, there are multiple answers about type hinting. This is the technical solution. But you should also make sure that the whole design is sensible and intuitive. This will make type problems and mistakes more rare.
Remember that even these type failures will be thrown at runtime. Make sure you have tests for the code.
Even in the case you describe, your script will crash, complaining there is no method / attribute X on the object Y so you'll know where does this come from.
Anyway, I think that always try to prevent grew up programmers to pass the wrong object to a method is not a good time investment : you could spend it in documenting and training instead.
Duck typing and careful colleagues is what you need, not additional checks that will make you app more rigid.
But it may be a Pythonista point of view...
#Eran Galperin's response is the preferred method for ensuring the object you are using is of the correct type.
Also worth noting is the instanceOf operator - it is helpful for when you want to check that an object is one of multiple types.
You can set the error_reporting ini setting in your php.ini file or use error_reporting function to set it in run time

Categories