-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sniff warning when method returns a primitive #88
Comments
Primitives idea is good but it can be improved. In my opinion when sending/returning an array or an object that can be modified is the most important thing that we should prevent when communicating between objects. Arrays are like a black box, we never know what are really inside them until we open them, therefore checks must be performed before do it. Also they are mutable, therefore open the doors for inconsistencies in our code. Objects are not immutable and they are also an open door for bugs and inconsistency across the code, once they state can be inadvertently changed once they are passed around by reference, therefore they MUST NOT be used to pass data between objects. The solution is to enforce the use of Immutable Value Objects to sent/return data when it needs to be passed between objects. So the check should ensure that the returned object is an Immutable Value Object, but here is where things get really hard once we don't have such thing natively in PHP. An Immutable Value Object Must:
Trait ExampleThis trait is extracted from production code. <?php declare(strict_types = 1);
namespace Nn4m\ImmutableValuesObject\Traits;
use LogicException;
/**
* @author Exadra37 <exadra37ingmailpointcom>
* @since 12 April 2017
*/
/**
* Let's try to enforce as much as possible that the Immutable Values Object we create using this Trait can't be mutated.
*
* Ensures we can't:
* - get any porperty that does not have the Accessor public method.
* - set any property.
* - unset a property.
* - perform validations like isset() or empty() on properties.
* - clone the object.
*
* Remember also to declare the Class as final so it can't be extended.
*/
trait EnforceImmutableValuesObjectTrait
{
/**
* Don't allow to call a property directly.
*
* This will enforce the use of Accessors methods to get their values.
*
* @throws LogicException When we try to call directly a property in the class.
*
* @param string $propertyName The property name.
*
* @return void
*/
public function __get(string $propertyName)
{
throw new LogicException("Can't get property {$propertyName} directly on a Immutable Object at {$this->buildCaller(debug_backtrace()[1])}");
}
/**
* Don't allow to set a value in any property of the Class.
*
* Also prevents the creation of properties in the class.
*
* @throws LogicException When we try to set or create a property in the class.
*
* @param string $propertyName The property name.
* @param mix $value The proerty value to be setted.
*
* @return void
*/
public function __set(string $propertyName, $value)
{
throw new LogicException("Can't set property {$propertyName} on a Immutable Object at {$this->buildCaller(debug_backtrace()[1])}");
}
/**
* Don't allow to unset a property in the class.
*
* @throws LogicException When we try to unset a property in the class.
*
* @param string $propertyName The property name.
*
* @return void
*/
public function __unset(string $propertyName)
{
throw new LogicException("Can't unset property {$propertyName} on a Immutable Object at {$this->buildCaller(debug_backtrace()[1])}");
}
/**
* Don't allow to perform isset() and empty() checks against a property in the class.
*
* @throws LogicException When we try to run isset() or empty() on a class property.
*
* @param string $propertyName The property name.
*
* @return void
*/
public function __isset(string $propertyName)
{
throw new LogicException("Can't perform check in property '{$propertyName}' on a Immutable Object at {$this->buildCaller(debug_backtrace()[1])}");
}
/**
* Don't allow the class to be cloned.
*
* @throws LogicException When we try to clone the class.
*
* @return void
*/
public function __clone()
{
throw new LogicException("Does not make sense to clone a Immutable Object at {$this->buildCaller(debug_backtrace()[1])}");
}
/**
* Build the caller that triggered the exception.
*
* We handle it differently depending if the caller is a class or just a plain php file.
*
* @link(Issue #3, http://gitlab.nn4m.net/nn4m/immutable-values-object/issues/3)
*
* @param array $trace The debug back trace from php.
*
* @return string with the name of the file/class, plus function/method name and line.
*/
private function buildCaller(array $trace): string
{
if (!empty($trace['class'])) {
return "{$trace['class']}{$trace['type']}{$trace['function']}():{$trace['line']}";
}
return "{$trace['file']} at function {$trace['function']}() on line {$trace['line']}";
}
} So if accepted my idea, the challenge here is how to check for an Immutable Value Object that matches the definition I propose above. |
Thanks @Exadra37 I understand your point but I'm not sure if it is acceptable to ensure that every object returned from a method is a Immutable Value Object. There are many times where the value returned from a method will be an object but not an immutable one. My main goal with this sniff was to produce warnings when a method returns a primitive so that it gives the developer an opportunity to evaluate if it is possible to return an object instead. |
Just a warning to suggest to the developer to see if an object could be returned instead.
The text was updated successfully, but these errors were encountered: