Skip to content

Callculation::resizeMatricesExtend() overwrites all rows in the smaller matrix. #4451

Open
@mklepaczewski

Description

@mklepaczewski

The bug

Calling Callculation::resizeMatricesExtend() with matrices of different sizes overwrites all rows in the smaller matrix with the value found in the last row. I haven't found the expected behaviour of the method (comments of the method don't specify it), but I think the idea was to extend the smaller matrix with values found in the last row, not to overwrite all of it with the value found in the last row.

Example:

<?php
declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;

// Sample matrices to test with
$matrix1 = [[1], [3]];
$matrix2 = [[5], [8], [11]];

// Use reflection to make the protected method accessible
$calculation = new Calculation();
$reflectionMethod = new ReflectionMethod(Calculation::class, 'resizeMatricesExtend');
$reflectionMethod->setAccessible(true);

// Call the method using reflection
$reflectionMethod->invokeArgs($calculation, [&$matrix1, &$matrix2, count($matrix1), 1, count($matrix2), 1]);

echo "Matrix 1 after:\n";
print_r($matrix1);

(Presumably) Expected output:

$matrix1 = [ [1], [3], [3] ];

Actual output

$matrix1 = [ [3], [3], [3] ];

Relevant code:

if ($matrix1Rows < $matrix2Rows) {
$x = $matrix1[$matrix1Rows - 1];
for ($i = 0; $i < $matrix2Rows; ++$i) {
$matrix1[$i] = $x;
}
}

Note that the analogous code for columns does not overwrite the previous columns, it extends them with the last value:

if ($matrix1Columns < $matrix2Columns) {
for ($i = 0; $i < $matrix1Rows; ++$i) {
$x = $matrix1[$i][$matrix1Columns - 1];
for ($j = $matrix1Columns; $j < $matrix2Columns; ++$j) {
$matrix1[$i][$j] = $x;
}
}
}

Proposed change

            if ($matrix1Rows < $matrix2Rows) {
                $x = $matrix1[$matrix1Rows - 1];
                for ($i = matrix1Rows ; $i < $matrix2Rows; ++$i) {
                    $matrix1[$i] = $x;
                }
            }

Please note that analogous change should be done for case where $matrix2Rows < $matrix1Rows.

I can create a PR if the change is accepted.

Why it matters

We found that some formulas that work for us in Excel result in #CALC! in PhpSpreadsheet. As an example, the following type of formulas result in #CALC!: =FILTER(Products!M:M;(Products!K:K=D5)*(Products!L:L=E5)). Products!K:K=D5 and Products!L:L=E5 generate matrices of different sizes (for whatever reason). PhpSpreadsheet extends the smaller matrix and overwrites all of its values. In effect, FILTER() fails to match any rows and results in #CALC!

Expected result

I don't know if the above behaviour is expected, but I suspect it's a bug. I haven't found any description of this behaviour. If it's not a bug, documenting it might be a good idea.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions