定义的名称
定义的名称
MS Excel 和其他电子表格格式中有两种类型的已定义名称:命名范围和命名公式。它们可以为您的电子表格增添很多功能,但需要正确使用。
本文档中显示的所有代码的工作示例均可在/samples/DefinedNames文件夹中找到。
命名范围
命名范围提供对单元格或单元格范围的名称引用。然后您可以在公式中使用该名称引用该单元格。
举个例子,我将创建一个简单的计算器,将税添加到价格中。
// Set up some basic data
$worksheet
->setCellValue('A1', 'Tax Rate:')
->setCellValue('B1', '=19%')
->setCellValue('A3', 'Net Price:')
->setCellValue('B3', 12.99)
->setCellValue('A4', 'Tax:')
->setCellValue('A5', 'Price including Tax:');
// Define named ranges
$spreadsheet->addNamedRange( new \PhpOffice\PhpSpreadsheet\NamedRange('TAX_RATE', $worksheet, '=$B$1') );
$spreadsheet->addNamedRange( new \PhpOffice\PhpSpreadsheet\NamedRange('PRICE', $worksheet, '=$B$3') );
// Reference that defined name in a formula
$worksheet
->setCellValue('B4', '=PRICE*TAX_RATE')
->setCellValue('B5', '=PRICE*(1+TAX_RATE)');
echo sprintf(
'With a Tax Rate of %.2f and a net price of %.2f, Tax is %.2f and the gross price is %.2f',
$worksheet->getCell('B1')->getCalculatedValue(),
$worksheet->getCell('B3')->getValue(),
$worksheet->getCell('B4')->getCalculatedValue(),
$worksheet->getCell('B5')->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/SimpleNamedRange.php
这使得在 MS Excel 中查看生成的电子表格时更容易理解其中的公式。使用这些命名范围(为单元格提供有意义的、人性化的名称)可以立即明确公式的目的。我们不需要查找单元格B2来查看它是什么,名称就可以告诉我们。
而且,如果税率变为 16%,那么我们只需将单元格中的值更改B1为新的税率 ( =16%),或者如果我们想计算不同净价的税费,这将立即反映在所有引用这些命名范围的计算中。无论我在工作表中的哪个位置使用该命名范围,它始终引用单元格中的值B1。
事实上,因为我们在定义名称时需要指定一个工作表,所以该名称可从电子表格中的任何工作表中获得,并且始终表示B2此工作表中的单元格(但请参阅下面有关命名范围范围的注释)。
绝对命名范围
在上面的例子中,当我定义命名范围值(例如'=$B$1')时,我$在行和列之前都使用了。这使命名范围成为绝对引用。
另一个例子:
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Charge Rate/hour:')
->setCellValue('B1', '7.50')
->setCellValue('A3', 'Date')
->setCellValue('B3', 'Hours')
->setCellValue('C3', 'Charge');
// Define named range using an absolute cell reference
$spreadsheet->addNamedRange( new NamedRange('CHARGE_RATE', $worksheet, '=$B$1') );
$workHours = [
'2020-0-06' => 7.5,
'2020-0-07' => 7.25,
'2020-0-08' => 6.5,
'2020-0-09' => 7.0,
'2020-0-10' => 5.5,
];
// Populate the Timesheet
$startRow = 4;
$row = $startRow;
foreach ($workHours as $date => $hours) {
$worksheet
->setCellValue("A{$row}", $date)
->setCellValue("B{$row}", $hours)
->setCellValue("C{$row}", "=B{$row}*CHARGE_RATE");
$row++;
}
$endRow = $row - 1;
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(B{$startRow}:B{$endRow})")
->setCellValue("C{$row}", "=SUM(C{$startRow}:C{$endRow})");
echo sprintf(
'Worked %.2f hours at a rate of %.2f - Charge to the client is %.2f',
$worksheet->getCell("B{$row}")->getCalculatedValue(),
$worksheet->getCell('B1')->getValue(),
$worksheet->getCell("C{$row}")->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/AbsoluteNamedRange.php
因为命名范围CHARGE_RATE被定义为绝对单元格引用,所以B2无论在电子表格中的公式中引用什么位置,它始终引用单元格。
相对命名范围
前面的例子展示了一个简单的时间表,使用绝对参考的收费率,用于计算我们向客户收取的费用。
在我们的公式中使用B{$row}(至少如果我们保存文件并打开它,它将在 MS Excel 中显示为实际单元格引用)需要一点思维敏捷才能记住该列B是我们当天的营业时间。为什么我们不能使用另一个名为 的命名范围HOURS_PER_DAY来使公式更易于阅读和有意义。
但是如果我们使用绝对命名范围HOURS_PER_DAY,那么我们需要为每一天(、等)使用不同的命名范围MONDAY_HOURS_PER_DAY,TUESDAY_HOURS_PER_DAY并且为一周中的每一天使用不同的公式;如果我们保留每月的时间表,我们将不得不为每月的每一天定义不同的命名范围……而这会带来比它本身更多的麻烦,并且很快就会变得难以管理。
这是相对命名范围非常有用的地方。
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Charge Rate/hour:')
->setCellValue('B1', '7.50')
->setCellValue('A3', 'Date')
->setCellValue('B3', 'Hours')
->setCellValue('C3', 'Charge');
// Define named ranges
// CHARGE_RATE is an absolute cell reference that always points to cell B1
$spreadsheet->addNamedRange( new NamedRange('CHARGE_RATE', $worksheet, '=$B$1') );
// HOURS_PER_DAY is a relative cell reference that always points to column B, but to a cell in the row where it is used
$spreadsheet->addNamedRange( new NamedRange('HOURS_PER_DAY', $worksheet, '=$B1') );
$workHours = [
'2020-0-06' => 7.5,
'2020-0-07' => 7.25,
'2020-0-08' => 6.5,
'2020-0-09' => 7.0,
'2020-0-10' => 5.5,
];
// Populate the Timesheet
$startRow = 4;
$row = $startRow;
foreach ($workHours as $date => $hours) {
$worksheet
->setCellValue("A{$row}", $date)
->setCellValue("B{$row}", $hours)
->setCellValue("C{$row}", "=HOURS_PER_DAY*CHARGE_RATE");
$row++;
}
$endRow = $row - 1;
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(B{$startRow}:B{$endRow})")
->setCellValue("C{$row}", "=SUM(C{$startRow}:C{$endRow})");
echo sprintf(
'Worked %.2f hours at a rate of %.2f - Charge to the client is %.2f',
$worksheet->getCell("B{$row}")->getCalculatedValue(),
$worksheet->getCell('B1')->getValue(),
$worksheet->getCell("C{$row}")->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/RelativeNamedRange.php
HOURS_PER_DAY( )单元格定义的区别'=$B1'在于,我们$在列 前面有一个B,但在行号前面没有。 使$列成为绝对列:无论我们在工作表中的哪个位置使用此名称,它始终引用列B。 如果在行号前面没有,我们将行号设为相对行号,即相对于公式中出现名称的行,因此它在执行计算时$会有效地用自己的行号替换。1
当它在第 4 行的公式中被使用时,它引用单元格B4,当它出现在第 5 行时,它引用单元格B5,依此类推。使用相对命名范围,我们可以使用相同的命名范围来引用不同行(和/或不同列)中的单元格,因此我们可以重复使用相同的命名范围来引用相对于我们使用它们的行(或列)的不同单元格。
命名范围不仅限于单个单元格,还可以指向一系列单元格。一种常见的用例可能是在数据集底部提供一系列列总计。让我们以时间表为例,并对其进行一些修改,以便为此目的使用相对列范围。
我不会复制前面示例中的整个代码,因为我只更改了几行;但我们只需替换块:
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(B{$startRow}:B{$endRow})")
->setCellValue("C{$row}", "=SUM(C{$startRow}:C{$endRow})");
和:
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
$spreadsheet->addNamedRange( new NamedRange('COLUMN_DATA_VALUES', $worksheet, "=A\${$startRow}:A\${$endRow}") );
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(COLUMN_DATA_VALUES)")
->setCellValue("C{$row}", "=SUM(COLUMN_DATA_VALUES)");
/samples/DefinedNames/RelativeNamedRange2.php
现在,我在 的定义中将列指定为相对的,COLUMN_DATA_VALUES其地址为 列A,而行是绝对的。当在 列 中使用相同的 相对命名范围 时B,它引用 列 中的单元格B而不是A;当在 列 中使用时C,它引用 列 中的单元格C。
虽然我们仍然有一段"=A\${$startRow}:A\${$endRow}"不易被人类阅读的代码(),但是当我们在 MS Excel 中打开生成的电子表格时,单元格中显示的总计公式立即就可以理解。
命名范围
每当我们定义一个命名范围时,我们都需要指定一个工作表,然后该名称可从电子表格中的任何工作表中获得,并且始终表示指定工作表中的单元格或单元格范围。
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Charge Rate/hour:')
->setCellValue('B1', '7.50');
// Define a global named range on the first worksheet for our Charge Rate
// CHARGE_RATE is an absolute cell reference that always points to cell B1
// Because it is defined globally, it will still be usable from any worksheet in the spreadsheet
$spreadsheet->addNamedRange( new NamedRange('CHARGE_RATE', $worksheet, '=$B$1') );
// Create a second worksheet as our client timesheet
$worksheet = $spreadsheet->addSheet(new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet($spreadsheet, 'Client Timesheet'));
// Define named ranges
// HOURS_PER_DAY is a relative cell reference that always points to column B, but to a cell in the row where it is used
$spreadsheet->addNamedRange( new NamedRange('HOURS_PER_DAY', $worksheet, '=$B1') );
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Date')
->setCellValue('B1', 'Hours')
->setCellValue('C1', 'Charge');
$workHours = [
'2020-0-06' => 7.5,
'2020-0-07' => 7.25,
'2020-0-08' => 6.5,
'2020-0-09' => 7.0,
'2020-0-10' => 5.5,
];
// Populate the Timesheet
$startRow = 2;
$row = $startRow;
foreach ($workHours as $date => $hours) {
$worksheet
->setCellValue("A{$row}", $date)
->setCellValue("B{$row}", $hours)
->setCellValue("C{$row}", "=HOURS_PER_DAY*CHARGE_RATE");
$row++;
}
$endRow = $row - 1;
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
$spreadsheet->addNamedRange( new NamedRange('COLUMN_DATA_VALUES', $worksheet, "=A\${$startRow}:A\${$endRow}") );
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(COLUMN_DATA_VALUES)")
->setCellValue("C{$row}", "=SUM(COLUMN_DATA_VALUES)");
echo sprintf(
'Worked %.2f hours at a rate of %s - Charge to the client is %.2f',
$worksheet->getCell("B{$row}")->getCalculatedValue(),
$chargeRateCellValue = $spreadsheet
->getSheetByName($spreadsheet->getNamedRange('CHARGE_RATE')->getWorksheet()->getTitle())
->getCell($spreadsheet->getNamedRange('CHARGE_RATE')->getCellsInRange()[0])->getValue(),
$worksheet->getCell("C{$row}")->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/ScopedNamedRange.php
即使CHARGE_RATE引用不同工作表上的单元格,由于设置为全局(默认),因此可以从电子表格中的任何工作表访问它。因此,当我们在第二个时间表工作表的公式中引用它时,我们就能够从第一个工作表访问该值并将其用于计算。
但是,命名范围可以是局部范围,因此只有从特定工作表引用时才可用,也可以是全局范围。这意味着您可以在不同的工作表上使用具有不同值的相同命名范围名称。
进一步构建我们的时间表,也许我们对每个客户使用不同的工作表,并且在向大多数客户开具账单时使用相同的小时费率;但对于一个特定的客户(也许是为朋友工作),我们使用较低的费率。
$clients = [
'Client #1 - Full Hourly Rate' => [
'2020-0-06' => 2.5,
'2020-0-07' => 2.25,
'2020-0-08' => 6.0,
'2020-0-09' => 3.0,
'2020-0-10' => 2.25,
],
'Client #2 - Full Hourly Rate' => [
'2020-0-06' => 1.5,
'2020-0-07' => 2.75,
'2020-0-08' => 0.0,
'2020-0-09' => 4.5,
'2020-0-10' => 3.5,
],
'Client #3 - Reduced Hourly Rate' => [
'2020-0-06' => 3.5,
'2020-0-07' => 2.5,
'2020-0-08' => 1.5,
'2020-0-09' => 0.0,
'2020-0-10' => 1.25,
],
];
foreach ($clients as $clientName => $workHours) {
$worksheet = $spreadsheet->addSheet(new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet($spreadsheet, $clientName));
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Charge Rate/hour:')
->setCellValue('B1', '7.50')
->setCellValue('A3', 'Date')
->setCellValue('B3', 'Hours')
->setCellValue('C3', 'Charge');
;
// Define named ranges
// CHARGE_RATE is an absolute cell reference that always points to cell B1
$spreadsheet->addNamedRange( new NamedRange('CHARGE_RATE', $worksheet, '=$B$1', true) );
// HOURS_PER_DAY is a relative cell reference that always points to column B, but to a cell in the row where it is used
$spreadsheet->addNamedRange( new NamedRange('HOURS_PER_DAY', $worksheet, '=$B1', true) );
// Populate the Timesheet
$startRow = 4;
$row = $startRow;
foreach ($workHours as $date => $hours) {
$worksheet
->setCellValue("A{$row}", $date)
->setCellValue("B{$row}", $hours)
->setCellValue("C{$row}", "=HOURS_PER_DAY*CHARGE_RATE");
$row++;
}
$endRow = $row - 1;
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
$spreadsheet->addNamedRange( new NamedRange('COLUMN_TOTAL', $worksheet, "=A\${$startRow}:A\${$endRow}", true) );
++$row;
$worksheet
->setCellValue("B{$row}", "=SUM(COLUMN_TOTAL)")
->setCellValue("C{$row}", "=SUM(COLUMN_TOTAL)");
}
$spreadsheet->removeSheetByIndex(0);
// Set the reduced charge rate for our special client
$worksheet
->setCellValue("B1", 4.5);
foreach ($spreadsheet->getAllSheets() as $worksheet) {
echo sprintf(
'Worked %.2f hours for "%s" at a rate of %.2f - Charge to the client is %.2f',
$worksheet->getCell("B{$row}")->getCalculatedValue(),
$worksheet->getTitle(),
$worksheet->getCell('B1')->getValue(),
$worksheet->getCell("C{$row}")->getCalculatedValue()
), PHP_EOL;
}
/samples/DefinedNames/ScopedNamedRange2.php
现在,我们为三个不同的客户分别创建三个工作表。由于每个命名范围都链接到一个工作表,因此我们需要创建三组命名范围,这样我们就不会简单地引用其中一个工作表上的单元格;但是因为我们在本地限定它们的作用域(请注意定义命名范围时使用的额外布尔参数),我们可以在每个工作表上使用相同的名称,并且当我们在该工作表的公式中使用它们时,它们将引用正确的单元格。
在评估命名范围时,逻辑首先查看当前工作表是否定义了本地范围的命名范围。如果有,那么这就是将在计算中使用的命名范围。如果没有找到具有该名称的本地范围的命名范围,逻辑将查看是否存在全局范围的命名范围定义,如果找到,将使用该定义。如果未找到当前工作表范围内或全局范围内的所需名称的命名范围,则将#NAME返回错误。
命名公式
命名公式是存储的公式或公式的一部分,可以在单元格中通过名称引用,并在电子表格内的许多不同位置重复使用。
作为示例,我将修改我创建的简单税收计算器作为命名范围的示例。
// Add some Named Formulae
// The first to store our tax rate
$spreadsheet->addNamedFormula(new NamedFormula('TAX_RATE', $worksheet, '=19%'));
// The second to calculate the Tax on a Price value (Note that `PRICE` is defined later as a Named Range)
$spreadsheet->addNamedFormula(new NamedFormula('TAX', $worksheet, '=PRICE*TAX_RATE'));
// Set up some basic data
$worksheet
->setCellValue('A1', 'Tax Rate:')
->setCellValue('B1', '=TAX_RATE')
->setCellValue('A3', 'Net Price:')
->setCellValue('B3', 19.99)
->setCellValue('A4', 'Tax:')
->setCellValue('A5', 'Price including Tax:');
// Define a named range that we can use in our formulae
$spreadsheet->addNamedRange(new NamedRange('PRICE', $worksheet, '=$B$3'));
// Reference the defined formulae in worksheet formulae
$worksheet
->setCellValue('B4', '=TAX')
->setCellValue('B5', '=PRICE+TAX');
echo sprintf(
'With a Tax Rate of %.2f and a net price of %.2f, Tax is %.2f and the gross price is %.2f',
$worksheet->getCell('B1')->getCalculatedValue(),
$worksheet->getCell('B3')->getValue(),
$worksheet->getCell('B4')->getCalculatedValue(),
$worksheet->getCell('B5')->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/SimpleNamedFormula.php
这里有几点需要注意:
首先,我们实际上是将税率存储在命名公式 ( TAX_RATE) 中,而不是作为单元格值。当我们在单元格中显示税率时B1,我们实际上是在存储一条指令,让 MS Excel 评估公式并在该单元格中显示结果。
然后,我们使用一个命名公式TAX,该公式引用另一个命名公式(TAX_RATE)和一个命名范围(PRICE),并使用它们两者执行计算(PRICE * TAX_RATE)。
最后,我们在两个不同的上下文中使用该公式TAX。第一次显示税值(在单元格中B4);第二次作为另一个公式的一部分(PRICE + TAX在单元格中)B5。
命名公式不仅限于简单的数学,还可以包括 MS EXcel 函数以提供很大的灵活性;并且它们可以引用其他工作表上的值。
$worksheet = $spreadsheet->setActiveSheetIndex(0);
setYearlyData($worksheet,'2019', $data2019);
$worksheet = $spreadsheet->addSheet(new Worksheet($spreadsheet));
setYearlyData($worksheet,'2020', $data2020);
$worksheet = $spreadsheet->addSheet(new Worksheet($spreadsheet));
setYearlyData($worksheet,'2020', [], 'GROWTH');
function setYearlyData(Worksheet $worksheet, string $year, $yearlyData, ?string $title = null) {
// Set up some basic data
$worksheetTitle = $title ?: $year;
$worksheet
->setTitle($worksheetTitle)
->setCellValue('A1', 'Month')
->setCellValue('B1', $worksheetTitle === 'GROWTH' ? 'Growth' : 'Sales')
->setCellValue('C1', $worksheetTitle === 'GROWTH' ? 'Profit Growth' : 'Margin')
->setCellValue('A2', Date::stringToExcel("{$year}-01-01"));
for ($row = 3; $row <= 13; ++$row) {
$worksheet->setCellValue("A{$row}", "=NEXT_MONTH");
}
if (!empty($yearlyData)) {
$worksheet->fromArray($yearlyData, null, 'B2');
} else {
for ($row = 2; $row <= 13; ++$row) {
$worksheet->setCellValue("B{$row}", "=GROWTH");
$worksheet->setCellValue("C{$row}", "=PROFIT_GROWTH");
}
}
$worksheet->getStyle('A1:C1')
->getFont()->setBold(true);
$worksheet->getStyle('A2:A13')
->getNumberFormat()
->setFormatCode('mmmm');
$worksheet->getStyle('B2:C13')
->getNumberFormat()
->setFormatCode($worksheetTitle === 'GROWTH' ? '0.00%' : '_-€* #,##0_-');
}
// Add some Named Formulae
// The first to store our tax rate
$spreadsheet->addNamedFormula(new NamedFormula('NEXT_MONTH', $worksheet, "=EDATE(OFFSET(\$A1,-1,0),1)"));
$spreadsheet->addNamedFormula(new NamedFormula('GROWTH', $worksheet, "=IF('2020'!\$B1=\"\",\"-\",(('2020'!\$B1/'2019'!\$B1)-1))"));
$spreadsheet->addNamedFormula(new NamedFormula('PROFIT_GROWTH', $worksheet, "=IF('2020'!\$C1=\"\",\"-\",(('2020'!\$C1/'2019'!\$C1)-1))"));
for ($row = 2; $row<=7; ++$row) {
$month = $worksheet->getCell("A{$row}")->getFormattedValue();
$growth = $worksheet->getCell("B{$row}")->getFormattedValue();
$profitGrowth = $worksheet->getCell("C{$row}")->getFormattedValue();
echo "Growth for {$month} is {$growth}, with a Profit Growth of {$profitGrowth}", PHP_EOL;
}
/samples/DefinedNames/CrossWorksheetNamedFormula.php
这里我们创建了两个命名公式,它们都使用函数IF(),比较两个不同工作表上的值,并计算两者之间的百分比差异。我们还创建了一个命名公式,它使用函数OFFSET()引用当前相对单元格引用上方的单元格。
组合命名范围和公式
对于结合命名范围和命名公式的稍微复杂一点的示例,我们可以在客户时间表上构建。
// Set up some basic data for a timesheet
$worksheet
->setCellValue('A1', 'Charge Rate/hour:')
->setCellValue('B1', '7.50')
->setCellValue('A3', 'Date')
->setCellValue('B3', 'Hours')
->setCellValue('C3', 'Charge');
// Define named ranges
// CHARGE_RATE is an absolute cell reference that always points to cell B1
$spreadsheet->addNamedRange(new NamedRange('CHARGE_RATE', $worksheet, '=$B$1'));
// HOURS_PER_DAY is a relative cell reference that always points to column B, but to a cell in the row where it is used
$spreadsheet->addNamedRange(new NamedRange('HOURS_PER_DAY', $worksheet, '=$B1'));
// Set up the formula for calculating the daily charge
$spreadsheet->addNamedFormula(new NamedFormula('DAILY_CHARGE', null, '=HOURS_PER_DAY*CHARGE_RATE'));
// Set up the formula for calculating the column totals
$spreadsheet->addNamedFormula(new NamedFormula('COLUMN_TOTALS', null, '=SUM(COLUMN_DATA_VALUES)'));
$workHours = [
'2020-0-06' => 7.5,
'2020-0-07' => 7.25,
'2020-0-08' => 6.5,
'2020-0-09' => 7.0,
'2020-0-10' => 5.5,
];
// Populate the Timesheet
$startRow = 4;
$row = $startRow;
foreach ($workHours as $date => $hours) {
$worksheet
->setCellValue("A{$row}", $date)
->setCellValue("B{$row}", $hours)
->setCellValue("C{$row}", '=DAILY_CHARGE');
++$row;
}
$endRow = $row - 1;
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
$spreadsheet->addNamedRange(new NamedRange('COLUMN_DATA_VALUES', $worksheet, "=A\${$startRow}:A\${$endRow}"));
++$row;
$worksheet
->setCellValue("B{$row}", '=COLUMN_TOTALS')
->setCellValue("C{$row}", '=COLUMN_TOTALS');
echo sprintf(
'Worked %.2f hours at a rate of %.2f - Charge to the client is %.2f',
$worksheet->getCell("B{$row}")->getCalculatedValue(),
$worksheet->getCell('B1')->getValue(),
$worksheet->getCell("C{$row}")->getCalculatedValue()
), PHP_EOL;
/samples/DefinedNames/NamedFormulaeAndRanges.php
本例中需要注意的要点是,您必须为命名范围指定工作表,但命名公式则不需要;事实上,为命名公式指定工作表可能会导致打开已保存文件时出现 MS Excel 错误。通常,创建命名公式时指定空工作表值更为安全,除非它明确引用单元格值,或者您希望将其范围限定在该工作表中。
我们定义命名范围和公式的顺序也无关紧要,即使有些依赖于其他:这只在我们尝试在单元格计算中使用它们时或保存文件时才重要;只要每个定义的名称都已在此时定义,那么它就不重要。在这种情况下,我们无法定义,直到COLUMN_DATA_VALUES我们了解它需要包含的行范围;但我们仍然可以COLUMN_TOTALS在那之前定义公式。
补充评论
帮手
到目前为止的所有示例中,我们均明确使用了NamedRange和NamedFormula类以及电子表格的addNamedRange()和addNamedFormula()方法,例如
$spreadsheet->addNamedRange(new NamedRange('HOURS_PER_DAY', $worksheet, '=$B1'));
但是,如果我们意外地为命名范围设置了公式值,或者为命名公式设置了范围值,则可能会导致错误。
作为辅助程序,DefinedName 类提供了一个静态方法,可以识别值表达式是 Range 还是 Formula,并实例化适当的类。
$this->spreadsheet->addDefinedName(
DefinedName::createInstance('FOO', $this->spreadsheet->getSheetByName('Sheet #2'), '=16%', true)
);
命名
您分配给已定义名称的名称必须遵循以下规则: - 名称的第一个字符必须是以下字符之一: - 字母(包括 UTF-8 字母) - 下划线 ( _) - 名称中的其余字符可以是 - 字母(包括 UTF-8 字母) - 数字(包括 UTF-8 数字) - 句点 ( .) - 下划线字符 ( _) - 不允许使用以下字符: - 不允许将空格字符作为名称的一部分。 - 名称不能类似于单元格地址,例如 A35 或 R2C2 - 名称不区分大小写。例如,North和NORTH被视为同一名称。
限制
PHPSpreadsheet 尚未完全验证您使用的名称,因此有可能在 PHPSpreadsheet 中创建的电子表格在您保存并尝试在 MS Excel 中打开时会崩溃;或者在单元格中引用它们时会崩溃 PHPSpreadsheet。因此,请在创建名称时保持理智,并遵循上面列出的规则。
没有什么可以阻止你创建与现有函数名称匹配的定义名称
$spreadsheet->addNamedFormula(new NamedFormula('SUM', $worksheet, '=SUM(A1:E5)'));
这在 MS Excel 中可以毫无问题地运行。但是,不能保证它在 PHPSpreadsheet 中正常工作;而且肯定会给阅读它的人造成困惑;所以不推荐这样做。名称的存在是为了给阅读电子表格的人提供清晰度,包含 的单元格=SUM比包含 的单元格更难理解(它是总和是多少?)=SUM(B4:B8)。使用提供含义的名称,例如SUM_OF_WORKED_HOURS。
除非命名范围和命名公式的范围不同,否则它们不能具有相同的名称。
MS Excel 使用一些“特殊技巧”来模拟相对命名范围,其中行或列位于当前行或列之前,如果您想要获取不包含当前单元格的列总计,则非常有用。PHPSpreadsheet 不支持这些“技巧”,但可以使用OFFSET()命名公式中的函数进行模拟。在我们的RelativeNamedRange2.php示例中,我们仅使用我们知道应该包含的行明确创建了COLUMN_DATA_VALUES命名范围,这样我们就不会包含当前行(我们显示总计的位置)并创建循环引用:
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
$spreadsheet->addNamedRange(new NamedRange('COLUMN_DATA_VALUES', $worksheet, "=A\${$startRow}:A\${$endRow}"));
我们可以创建一个命名函数来OFFSET()指定起始行,并将结束行偏移 -1 行:
// COLUMN_TOTAL is another relative cell reference that always points to the same range of rows but to cell in the column where it is used
// To avoid including the current row,or having to hard-code the range itself (as we did in the previous example)
// we wrap it in a named formula using the OFFSET() function
$spreadsheet->addNamedFormula(new NamedFormula('COLUMN_DATA_VALUES', $worksheet, "=OFFSET(A\$4:A1, -1, 0)"));
如示例所示RelativeNamedRangeAsFunction.php。
技术 2024-07-23 17:07:31 通过 网页 浏览(1211)
共有0条评论!