PHPCS rule for type hinting - php-7.1

Is there a rule to check all functions for type hinting?
/**
* Set the part name.
*
* #param string $name The part name.
*/
public function setName(string $name) : void
{
$this->name = $name;
}
So for example it has to have a type in front of the argument and the function has to have a specified return type.

2019 update - even Smarter
In time, my previous answer - TypeHintDeclarationSniff - has shown as very buggy. To be specific:
public function anotherMethod(int $value)
{
// $value is known integer
$this->someMethod($value);
}
/**
* #param string $value
*/
-private function someMethod($value)
+private function someMethod(string $value) // here should be "int"
{
}
Missed cases:
public function getItems() // here should be "array"
{
return ['Statie', 'EasyCodingStandard', 'Rector'];
}
Or:
public function getResult() // here should be "float"
{
if (true) {
return 5.2;
}
return 5.3;
}
Or even breaks the code with parent type in /vendor. Why? Because it's based on strings and token, not a static analysis of the code.
This made many people very angry, after I recommended them this sniff. Obviously.
How to do it Better?
I wrote a tool called Rector (https://github.com/rectorphp/rector), that takes into account other variables and other classes and their types.
That way you can complete type declarations to a code without any #param or #return annotations.
How to use It?
Install:
composer require vendor/bin/rector
Setup rector.yaml config:
# rector.yaml
services:
Rector\Php\Rector\FunctionLike\ParamTypeDeclarationRector: ~
Rector\Php\Rector\FunctionLike\ReturnTypeDeclarationRector: ~
Use:
vendor/bin/rector process src --dry-run # preview
vendor/bin/rector process src # change
That's it!
Read Behind the Scenes
How to Complete Type Declarations without Docblocks with Rector
The Rocket Science Behind Migration of Docblock Types to PHP Typehints
Initial answer:
You can use TypeHintDeclarationSniff from Slevomat/CodingStandard for this.
I use it for over a year and it works perfectly.

Related

Change output names in API return object

I am very new to nodejs and typescript.
I have try to provide an API via express.
I have try to return a custom object on my API who looks like that :
export class Auction {
private _currentPrice:number = 0;
private _auctionName:string;
public constructor(currentPrice: number , auctionName: string) {
this._currentPrice = currentPrice;
this._auctionName = auctionName;
}
/**
* Getter auctionName
* #return {string}
*/
public get auctionName(): string {
return this._auctionName;
}
/**
* Setter auctionName
* #param {string} value
*/
public set auctionName(value: string) {
this._auctionName = value;
}
/**
* Setter currentPrice
* #param {number } value
*/
public set currentPrice(value: number ) {
this._currentPrice = value;
}
/**
* Getter currentPrice
* #return {number }
*/
public get currentPrice(): number {
return this._currentPrice;
}
}
But what I have seen is that the answer of my API is something like :
{"_currentPrice":0,"_auctionName":"toto"}
I was expecting something like
{"currentPrice":0,"auctionName":"toto"}
Is there any way to automaticaly convert it to the format I want ?
This is happening because when the TypeScript is compiled to JavaScript, objects created by that class have public _currentPrice and _auctionName properties (because TypeScript "private" properties are only private in terms of TypeScript's type system) and they don't have their own currentPrice and auctionName properties (they inherit them from their prototype, which has them as accessor properties). JSON.stringify only includes "own" properties.
You can deal with it in a few ways:
By using simple properties for currentPrice and auctionName. You have public accessors for both get and set for both properties, so there doesn't seem to be any reason to use private properties to hold their values. Or,
By providing your own toJSON method for the class:
toJSON() {
return {currentPrice: this._currentPrice, auctionName: this._auctionName};
}
Despite the name "toJSON", this method isn't supposed to return JSON; it's supposed to return the value for the object that should be converted to JSON. So in this case, you return an object with the properties you want the returned JSON to have.
A third solution would be to use JavaScript's own private properties (they're supported in up-to-date Node.js versions) and "own" accessors for them on the objects, but I don't think TypeScript supports JavaScript's private properties yet.

Custom GroovyDocTool not finding anything

I'm having difficulty using GroovyDocTool.
No matter what paths I pass into it, my rootDoc does not resolve to any packages, classes, or methods. I have to assume I'm just passing in the wrong paths, but for the life of me can't figure out what to pass.
class TestGroovyDoclet extends GroovyDocTool{
public TestGroovyDoclet() {
super([
'~/ ... /src/'
,'/home/ ... /src/ ... /Sample/'
,'/home/ ... /src/ ... /Sample/Results.groovy'
]);
}
public void Execute(){
System.out.println('Begin Processing Javadoc');
System.out.format(' p %d\n', rootDoc.specifiedPackages().length);
System.out.format(' c %d\n', rootDoc.classes().length);
System.out.println('Finished Processing Javadoc');
}
public static void main(String[] args){
(new TestGroovyDoclet()).with{
it.Execute();
}
}
}
What are considered valid parameters to pass into the GroovyRootDocBuilder?
The authors of GroovyDoc appear to have intended for its use from Ant. This means that there is no means to look up the files to be processed, since you should already know what files you are processing. The consumer must specify the individual files to be processed, and call buildPath to actually process the files. (see override of buildPath)
For those only wanting to interact with the Document Tree, GroovyDocTool is really of no value, and users would likely be better extending GroovyRootDocBuilder which actually contains the meat of the processing. If you are doing this, you may as well re-write the constructor to hide away GroovyDocTool altogether. (see the new Constructor)
class TestGroovyDoclet extends GroovyRootDocBuilder{
protected def sourcepaths = [];
public TestGroovyDoclet() {
//HARDCODE: some test values for my testing
this([
'~/ ... /src/'
,'/home/ ... /src/ ... /Sample/'
,'/home/ ... /src/ ... /Sample/Results.groovy'
]);
}
public TestGroovyDoclet(String[] sourcepaths) {
//hide the unused GroovyDocTool
super(new GroovyDocTool(), sourcepaths, new ArrayList<LinkArgument>(), new Properties());
this.sourcepaths = sourcepaths;
}
/**
* Builds the tree by recursively searching for files
* <p>
* It is likely useful to override the original buildTree
* method as well to put some safeties in place. The parsing
* routines do not do a lot of validation. For those of us
* inheritting, it would be a good idea to override build
* tree ot sanitize the input list as much as possible.
* </p>
*/
#Override
public void buildTree(){
def list = [];
// loop through the sourcepaths to recursively find the files
for (String sourcepath : sourcepaths) {
def root = new File(sourcepath);
if(root.exists()){
if(root.isFile()){
list << root.absolutePath;
}
else{
root.eachFileRecurse (FileType.FILES) { file -> list << file.absolutePath; };
}
}
}
buildTree(list);
}
/**
* Method to actually do the processing. Sample only, does not demonstrate anything useful.
*/
public void Execute(){
buildTree();
System.out.println('Begin Processing GroovyDoc');
System.out.format(' p %d\n', rootDoc.specifiedPackages().length);
//System.out.format(' c %d\n', rootDoc.classes().length);
int count = 0;
for(def p : rootDoc.specifiedPackages()){
count += p.allClasses().length;
}
System.out.format(' c %d\n', count);
System.out.println('Finished Processing GroovyDoc');
}
public static void main(String[] args){
(new TestGroovyDoclet()).with{
it.Execute();
}
}
}
The above code is not perfect, and not exactly what I came up with; rather the code is meant to highlight a few of the faulty assumptions contained in the OP, and mechanisms to work around them. It is not gauranteed to compile since it just cut/pastes elements of a larger re-write.
Weirdness:
Interestingly GroovyRootDoc.classes always returns null (unsure why). It was necessary to loop through each package, and inspect the classes that are a subset of each. This was surprising, but the desired usage anyway.
The code above only worked on groovy files, not java. I think GroovyDoc choked on some java1.8 syntax (but I'm not sure).

In Haxe, how do you pass Enum values in functions, and then convert them to Strings within the function?

I can't seem to get this working, but I'd be surprised if it wasn't possible in Haxe.
I'm trying to pass a couple of Enum values defined in my game to a function, so that it can then concatenate them as String types and pass that to other functions.
Example:
// In a general Entity class:
public override function kill():Void {
messages.dispatchCombined(entityType, ListMessages.KILLED);
super.kill();
}
And in my Messages.hx class:
package common;
import msignal.Signal.Signal1;
/**
* A Message / Event class using Signals bound to String names.
* #author Pierre Chamberlain
*/
class Messages{
var _messages:MessagesDef;
public function new() {
_messages = new MessagesDef();
}
public function add(pType:String, pCallback:FuncDef) {
if (_messages[pType] == null) {
_messages[pType] = new Signal1<Dynamic>();
}
var signals = _messages[pType];
signals.add( pCallback );
}
public function dispatch(pType:String, pArg:Dynamic):Bool {
var signals = _messages[pType];
if (signals == null) return false;
signals.dispatch(pArg);
return true;
}
//Compiler doesn't like passing enums :(
public inline function addCombined(pSource:Enum, pEvent:Enum, pCallback:FuncDef) {
add( combine(pSource, pEvent), pCallback );
}
public inline function dispatchCombined(pSource:Enum, pEvent:Enum, pArg:Dynamic):Bool {
return dispatch( combine(pSource, pEvent), pArg);
}
//How can I just pass the enum "names" as strings?
static inline function combine(a:Enum, b:Enum):String {
return String(a) + ":" + String(b);
}
}
typedef MessagesDef = Map<String, Signal1<Dynamic>>;
typedef FuncDef = Dynamic->Void;
Note how addCombined, dispatchCombined and combine expect an "Enum" type, but in this case I'm not sure if Haxe actually expects the entire Enum "class" to be passed (ie: ListMessages instead of ListMessages.KILLED) or if a value should work. Anyways, compiler doesn't like it - so I'm assuming another special Type has to be used.
Is there another way to go about passing enums and resolving them to strings?
I think you need EnumValue as parameter type (if it is only for enum values), and use Std.String to convert to String values.
static inline function combine(a:EnumValue, b:EnumValue):String {
return Std.string(a) + ":" + Std.string(b);
}
Of course that can be written smaller using String interpolation:
static inline function combine(a:EnumValue, b:EnumValue):String {
return '$a:$b';
}
Of course that can be 'more dynamic' using type parameters:
static inline function combine<A, B>(a:A, b:B):String {
return '$a:$b';
}
There is totally no need to use Dynamic as suggested. If you use Dynamic, you basically turn off the type system.
live example:
http://try.haxe.org/#a8844
Use Dynamic instead of Enum or pass them as Strings right away since you can always convert to enum from String if you need it later.
Anyway pass the enum as enum:Dynamic and then call Std.string(enum);
EDIT: Using EnumValue is definitely better approach than Dynamic, I use Dynamic in these functions because I send more than just Enums there and I am not worried about type safety in that case.

Overriding parent methods with contravariant arguments

Basically, I want to override a parent class with different arguments. For example:
class Hold<T> {
public var value:T;
public function new(value:T) {
set(value);
}
public function set(value:T) {
this.value = value;
}
}
Then override that class, something like:
class HoldMore extends Hold<T> {
public var value2:T;
public function new(value:T, value2:T) {
super(value);
set(value, value2);
}
override public function set(value:T, value2:T) {
this.value = value;
this.value2 = value2;
}
}
Obviously this will return an error, Field set overloads parent class with different or incomplete type. Is there a way around this? I tried using a public dynamic function, and then setting set in the new() function, but that gave a very similar error. Any thoughts?
This is just a complement to #stroncium's answer, which is totally correct.
Here is an example how it could look like:
class Hold<T> {
public var value:T;
public function new(value:T) {
set(value);
}
public function set(value:T) {
this.value = value;
}
}
class HoldMore<T> extends Hold<T> {
public var value2:T;
public function new(value:T, value2:T) {
super(value);
setBoth(value, value2);
}
// you cannot override "set" with a different signature
public function setBoth(value:T, value2:T) {
this.value = value;
this.value2 = value2;
}
}
alternatively, you could use an array as parameter or a dynamic object holding multiple values in order to "set" them using the same method, but you loose some of the compiler's type checking.
If you wrote the base class you could add an optional argument to it, this would be a workaround though, not directly what you want to do.
In the current state it totally won't work. There is not only 1 problem, but few of them:
Type T is meaningless in context of this new class, you should either use some concrete type or template this class over T.
You can not change the number of arguments of function when overriding it. However you can add another function(with a different name) to accept 2 arguments and do what you want (which is the way you would use in most languages, by the way).
I don't really understand how you see a contravariance problem there. The actual problem is that haxe doesn't support function overload. (It actually does, the function signature is name + full type, but that's not what you would want to write nor support, and is mostly used for js/java externs.)
Unfortunately the language doesn't allow it.

Undefined variable error in ExpressionEngine plugin

I'm working on a plugin that does device detection based on an external library.
This is what I have so far:
class Deetector {
// public $return_data;
/**
* Constructor
*/
public function __construct()
{
$this->EE =& get_instance();
$this->EE->load->add_package_path(PATH_THIRD.'/deetector');
$this->EE->load->library('detector');
$this->return_data = "";
}
public function deetector()
{
return $ua->ua;
}
public function user_agent()
{
return $ua->ua;
}
// ----------------------------------------------------------------
/**
* Plugin Usage
*/
public static function usage()
{
ob_start();
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}
}
If I call {exp:deetector} I get no output in the template. If I call {exp:deetector:user_agent} I get Undefined variable: ua.
Ultimately I don't plan on setting up different functions for each of the variables that the Detector library returns but am just trying to get it to output something at the moment.
I had originally started doing this as an extension which added the Detector library's variables to the global variables array and that was working fine; it's only since trying to do it as a plugin that I've run into problems.
You haven't set $this->ua to anything. I assume it's a variable of the detector library you loaded, so you probably want to do something like this:
class Deetector {
public function __construct()
{
$this->EE =& get_instance();
// remove this line, it's probably not doing anything
// $this->EE->load->add_package_path(PATH_THIRD.'/deetector');
$this->EE->load->library('detector');
// note you use $this->return_data instead of "return blah" in the constructor
$this->return_data = $this->EE->detector->ua;
}
// remove this, you can't have both __construct() and deetector(), they mean the same thing
// public function deetector()
// {
// return $ua->ua;
// }
public function user_agent()
{
return $this->EE->detector->ua;
}
}
UPDATE:
I took a look at the Detector docs, and it doesn't follow normal library conventions (it defines the $ua variable when you include the file). For that reason you should ignore the standard EE load functions, and include the file directly:
class Deetector {
public function __construct()
{
$this->EE =& get_instance();
// manually include the detector library
include(PATH_THIRD.'/deetector/libraries/detector.php');
// save the local $ua variable so we can use it in other functions further down
$this->ua = $ua;
// output the user agent in our template
$this->return_data = $this->ua->ua;
}
}

Resources