Skip to content

Commit

Permalink
Add phpstan strict rules (#233)
Browse files Browse the repository at this point in the history
* Add phpstan strict rules

* Fix travis coveralls

* Add phpstan-phpunit strict rules

* Fix eigen decomposition test name and phpstan ingored error
  • Loading branch information
akondas authored Feb 16, 2018
1 parent 6ac61a8 commit 16dc16b
Show file tree
Hide file tree
Showing 33 changed files with 164 additions and 71 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ after_success:
- |
if [[ $PHPUNIT_FLAGS != "" ]]; then
wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.0.0/php-coveralls.phar
php coveralls.phar --verbose;
php php-coveralls.phar --verbose;
fi
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"php": "^7.1"
},
"require-dev": {
"phpstan/phpstan-phpunit": "^0.9.4",
"phpstan/phpstan-shim": "^0.9",
"phpstan/phpstan-strict-rules": "^0.9.0",
"phpunit/phpunit": "^7.0.0",
"symplify/coding-standard": "^3.1",
"symplify/easy-coding-standard": "^3.1"
Expand Down
91 changes: 90 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
includes:
- vendor/phpstan/phpstan-strict-rules/rules.neon
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-phpunit/rules.neon
- vendor/phpstan/phpstan-phpunit/strictRules.neon

parameters:
ignoreErrors:
- '#Phpml\\Dataset\\FilesDataset::__construct\(\) does not call parent constructor from Phpml\\Dataset\\ArrayDataset#'

# mocks
- '#PHPUnit_Framework_MockObject_MockObject#'

# wide range cases
- '#Call to function count\(\) with argument type array<int>\|Phpml\\Clustering\\KMeans\\Point will always result in number 1#'
- '#Parameter \#1 \$coordinates of class Phpml\\Clustering\\KMeans\\Point constructor expects array, array<int>\|Phpml\\Clustering\\KMeans\\Point given#'

# probably known value
- '#Variable \$j might not be defined#'
- '#Method Phpml\\Classification\\DecisionTree::getBestSplit\(\) should return Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf but returns Phpml\\Classification\\DecisionTree\\DecisionTreeLeaf\|null#'
- '#Call to an undefined method Phpml\\Helper\\Optimizer\\Optimizer::getCostValues\(\)#'
4 changes: 2 additions & 2 deletions src/Association/Apriori.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ public function __construct(float $support = 0.0, float $confidence = 0.0)
*/
public function getRules(): array
{
if (!$this->large) {
if (empty($this->large)) {
$this->large = $this->apriori();
}

if ($this->rules) {
if (!empty($this->rules)) {
return $this->rules;
}

Expand Down
26 changes: 13 additions & 13 deletions src/Classification/DecisionTree.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,15 @@ protected function getSplitLeaf(array $records, int $depth = 0): DecisionTreeLea
}

if ($allSame || $depth >= $this->maxDepth || count($remainingTargets) === 1) {
$split->isTerminal = 1;
$split->isTerminal = true;
arsort($remainingTargets);
$split->classValue = key($remainingTargets);
} else {
if ($leftRecords) {
if (!empty($leftRecords)) {
$split->leftLeaf = $this->getSplitLeaf($leftRecords, $depth + 1);
}

if ($rightRecords) {
if (!empty($rightRecords)) {
$split->rightLeaf = $this->getSplitLeaf($rightRecords, $depth + 1);
}
}
Expand Down Expand Up @@ -312,13 +312,13 @@ protected function getBestSplit(array $records): DecisionTreeLeaf
$split->value = $baseValue;
$split->giniIndex = $gini;
$split->columnIndex = $i;
$split->isContinuous = $this->columnTypes[$i] == self::CONTINUOUS;
$split->isContinuous = $this->columnTypes[$i] === self::CONTINUOUS;
$split->records = $records;

// If a numeric column is to be selected, then
// the original numeric value and the selected operator
// will also be saved into the leaf for future access
if ($this->columnTypes[$i] == self::CONTINUOUS) {
if ($this->columnTypes[$i] === self::CONTINUOUS) {
$matches = [];
preg_match("/^([<>=]{1,2})\s*(.*)/", (string) $split->value, $matches);
$split->operator = $matches[1];
Expand Down Expand Up @@ -349,11 +349,11 @@ protected function getBestSplit(array $records): DecisionTreeLeaf
protected function getSelectedFeatures(): array
{
$allFeatures = range(0, $this->featureCount - 1);
if ($this->numUsableFeatures === 0 && !$this->selectedFeatures) {
if ($this->numUsableFeatures === 0 && empty($this->selectedFeatures)) {
return $allFeatures;
}

if ($this->selectedFeatures) {
if (!empty($this->selectedFeatures)) {
return $this->selectedFeatures;
}

Expand All @@ -363,7 +363,7 @@ protected function getSelectedFeatures(): array
}

shuffle($allFeatures);
$selectedFeatures = array_slice($allFeatures, 0, $numFeatures, false);
$selectedFeatures = array_slice($allFeatures, 0, $numFeatures);
sort($selectedFeatures);

return $selectedFeatures;
Expand Down Expand Up @@ -406,7 +406,7 @@ protected static function isCategoricalColumn(array $columnValues): bool
// all values in that column (Lower than or equal to %20 of all values)
$numericValues = array_filter($columnValues, 'is_numeric');
$floatValues = array_filter($columnValues, 'is_float');
if ($floatValues) {
if (!empty($floatValues)) {
return false;
}

Expand All @@ -433,7 +433,7 @@ protected function setSelectedFeatures(array $selectedFeatures): void
*/
protected function getSplitNodesByColumn(int $column, DecisionTreeLeaf $node): array
{
if (!$node || $node->isTerminal) {
if ($node->isTerminal) {
return [];
}

Expand All @@ -444,11 +444,11 @@ protected function getSplitNodesByColumn(int $column, DecisionTreeLeaf $node): a

$lNodes = [];
$rNodes = [];
if ($node->leftLeaf) {
if ($node->leftLeaf !== null) {
$lNodes = $this->getSplitNodesByColumn($column, $node->leftLeaf);
}

if ($node->rightLeaf) {
if ($node->rightLeaf !== null) {
$rNodes = $this->getSplitNodesByColumn($column, $node->rightLeaf);
}

Expand All @@ -475,6 +475,6 @@ protected function predictSample(array $sample)
}
} while ($node);

return $node ? $node->classValue : $this->labels[0];
return $node !== null ? $node->classValue : $this->labels[0];
}
}
20 changes: 10 additions & 10 deletions src/Classification/DecisionTree/DecisionTreeLeaf.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ class DecisionTreeLeaf
public $columnIndex;

/**
* @var DecisionTreeLeaf
* @var ?DecisionTreeLeaf
*/
public $leftLeaf = null;
public $leftLeaf;

/**
* @var DecisionTreeLeaf
* @var ?DecisionTreeLeaf
*/
public $rightLeaf = null;
public $rightLeaf;

/**
* @var array
Expand All @@ -52,7 +52,7 @@ class DecisionTreeLeaf
public $classValue = '';

/**
* @var bool|int
* @var bool
*/
public $isTerminal = false;

Expand Down Expand Up @@ -103,12 +103,12 @@ public function getNodeImpurityDecrease(int $parentRecordCount): float
$nodeSampleCount = (float) count($this->records);
$iT = $this->giniIndex;

if ($this->leftLeaf) {
if ($this->leftLeaf !== null) {
$pL = count($this->leftLeaf->records) / $nodeSampleCount;
$iT -= $pL * $this->leftLeaf->giniIndex;
}

if ($this->rightLeaf) {
if ($this->rightLeaf !== null) {
$pR = count($this->rightLeaf->records) / $nodeSampleCount;
$iT -= $pR * $this->rightLeaf->giniIndex;
}
Expand Down Expand Up @@ -140,16 +140,16 @@ public function getHTML($columnNames = null): string

$str = "<table ><tr><td colspan=3 align=center style='border:1px solid;'>${value}</td></tr>";

if ($this->leftLeaf || $this->rightLeaf) {
if ($this->leftLeaf !== null || $this->rightLeaf !== null) {
$str .= '<tr>';
if ($this->leftLeaf) {
if ($this->leftLeaf !== null) {
$str .= '<td valign=top><b>| Yes</b><br>'.$this->leftLeaf->getHTML($columnNames).'</td>';
} else {
$str .= '<td></td>';
}

$str .= '<td>&nbsp;</td>';
if ($this->rightLeaf) {
if ($this->rightLeaf !== null) {
$str .= '<td valign=top align=right><b>No |</b><br>'.$this->rightLeaf->getHTML($columnNames).'</td>';
} else {
$str .= '<td></td>';
Expand Down
2 changes: 1 addition & 1 deletion src/Classification/Ensemble/AdaBoost.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public function predictSample(array $sample)
protected function getBestClassifier(): Classifier
{
$ref = new ReflectionClass($this->baseClassifier);
if ($this->classifierOptions) {
if (!empty($this->classifierOptions)) {
$classifier = $ref->newInstanceArgs($this->classifierOptions);
} else {
$classifier = $ref->newInstance();
Expand Down
2 changes: 1 addition & 1 deletion src/Classification/Ensemble/Bagging.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ protected function initClassifiers(): array
$classifiers = [];
for ($i = 0; $i < $this->numClassifier; ++$i) {
$ref = new ReflectionClass($this->classifier);
if ($this->classifierOptions) {
if (!empty($this->classifierOptions)) {
$obj = $ref->newInstanceArgs($this->classifierOptions);
} else {
$obj = $ref->newInstance();
Expand Down
2 changes: 1 addition & 1 deletion src/Classification/Linear/Adaline.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function __construct(
bool $normalizeInputs = true,
int $trainingType = self::BATCH_TRAINING
) {
if (!in_array($trainingType, [self::BATCH_TRAINING, self::ONLINE_TRAINING])) {
if (!in_array($trainingType, [self::BATCH_TRAINING, self::ONLINE_TRAINING], true)) {
throw new Exception('Adaline can only be trained with batch and online/stochastic gradient descent algorithm');
}

Expand Down
2 changes: 1 addition & 1 deletion src/Classification/Linear/DecisionStump.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ protected function trainBinary(array $samples, array $targets, array $labels): v

// Check the size of the weights given.
// If none given, then assign 1 as a weight to each sample
if ($this->weights) {
if (!empty($this->weights)) {
$numWeights = count($this->weights);
if ($numWeights != count($samples)) {
throw new Exception('Number of sample weights does not match with number of samples');
Expand Down
4 changes: 2 additions & 2 deletions src/Classification/Linear/LogisticRegression.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ public function __construct(
string $penalty = 'L2'
) {
$trainingTypes = range(self::BATCH_TRAINING, self::CONJUGATE_GRAD_TRAINING);
if (!in_array($trainingType, $trainingTypes)) {
if (!in_array($trainingType, $trainingTypes, true)) {
throw new Exception('Logistic regression can only be trained with '.
'batch (gradient descent), online (stochastic gradient descent) '.
'or conjugate batch (conjugate gradients) algorithms');
}

if (!in_array($cost, ['log', 'sse'])) {
if (!in_array($cost, ['log', 'sse'], true)) {
throw new Exception("Logistic regression cost function can be one of the following: \n".
"'log' for log-likelihood and 'sse' for sum of squared errors");
}
Expand Down
4 changes: 2 additions & 2 deletions src/Classification/Linear/Perceptron.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public function partialTrain(array $samples, array $targets, array $labels = [])

public function trainBinary(array $samples, array $targets, array $labels): void
{
if ($this->normalizer) {
if ($this->normalizer !== null) {
$this->normalizer->transform($samples);
}

Expand Down Expand Up @@ -196,7 +196,7 @@ protected function runGradientDescent(array $samples, array $targets, Closure $g
*/
protected function checkNormalizedSample(array $sample): array
{
if ($this->normalizer) {
if ($this->normalizer !== null) {
$samples = [$sample];
$this->normalizer->transform($samples);
$sample = $samples[0];
Expand Down
Loading

0 comments on commit 16dc16b

Please sign in to comment.