Skip to content

OnlyWritesOnParameter ​

info on by default

Group: Unused · PhpStorm name: OnlyWritesOnParameterInspection

A parameter, closure import or local variable that is only ever written to (elements appended, incremented, concatenated onto…) but never read is dead work: the changes are lost when the function returns (by-value semantics). Likewise a closure use import that the closure body never touches, or an inline assignment whose target is never read afterwards, is unused.

Example ​

IGNORE_INCLUDES = false:

php
<?php
class Report
{
    public function collect(array $rows, array &$sink, $tally, Closure $done, Iterator $it)
    {
        return function ($pending, array &$bucket) use ($rows, &$sink, $tally) {
            $pending['x'] = 1;
            $bucket[] = 2;
            $tally[] = 3;
        };
    }

    public function counters($hits, $misses, $sum, &$total, Iterator $it)
    {
        $hits++;
        --$misses;
        $sum *= 2;
        $total++;
        $it[] = 1;
    }

    public function inline_unused()
    {
        if (null !== ($pos = strpos('abc', 'b'))) {
            return true;
        }
        $map = [];
        $map[$key = 'k'] = 1;
        $map[$slot = 'z'] = 2;
        return $slot . count($map);
    }

    public function locals($flag)
    {
        $buffer = $other = [];
        if ($flag) {
            $buffer[] = 1;
        }
        $other .= 'x';

        $kept = '';
        $kept .= 'y';
        echo $kept ?? '';

        $alias = &$flag;
        $alias .= 'z';

        $unusedPlain = 5;
    }

    public function with_include($n, $path)
    {
        $n -= 1;
        require $path;
    }
}

function makeHandlers(ArrayObject $registry, array $plain, string $template)
{
    $store = new SplObjectStorage();
    $register = function ($name) use ($registry, $plain, $store) {
        $registry[$name] = true;          // E5b: object import, the write is visible
        $store[] = $name;                 // E5b: inferred SplObjectStorage
        $plain[$name] = true;
    };
    $render = function () use ($template, $registry) {
        require __DIR__ . '/view.php';    // E5c: the view may read $template and $registry
    };
    $noop = function () use ($template) {
        $inner = function () { include 'x.php'; };   // nested closure: its include does not count
    };
}

function silenced(array $out)
{
    /** Buffers. @noinspection OnlyWritesOnParameterInspection */
    $out['a'][] = 1;
    $out['b'][] = 2;
}

Reported:

  • line 6: Variable is never used.
  • line 7: Value is only written here and never read; the write is lost.
  • line 9: Value is only written here and never read; the write is lost.
  • line 15: Value is only written here and never read; the write is lost.
  • line 16: Value is only written here and never read; the write is lost.
  • line 17: Value is only written here and never read; the write is lost.
  • line 24: Variable is never used.
  • line 28: Variable is never used.
  • line 37: Value is only written here and never read; the write is lost.
  • line 39: Value is only written here and never read; the write is lost.
  • line 64: Value is only written here and never read; the write is lost.
  • line 69: Variable is never used.

Options ​

OptionTypeDefaultEffect
IGNORE_INCLUDESbooltrueWhen on, write-only findings are reported even if the scope contains include/require (which could read variables). When off, such scopes produce no W findings. U findings are unaffected.

Configure ​

In custos.json:

json
{
  "rules": {
    "OnlyWritesOnParameter": {
      "enabled": false,
      "options": {
        "IGNORE_INCLUDES": true
      }
    }
  }
}

Suppress ​

Before the statement or declaration (or the first statement of the file), either of:

php
// @custos-ignore OnlyWritesOnParameter

/**
 * @noinspection OnlyWritesOnParameterInspection
 */

Released under the MIT License. Rule catalogue modelled on Php Inspections (EA Extended); independent clean-room implementation.