declare

(PHP 4, PHP 5, PHP 7, PHP 8)

declare 结构用于为代码块设置执行指令。 declare 的语法类似于其他流程控制结构的语法

declare (directive)
    statement

directive 部分允许设置 declare 块的行为。目前只识别三个指令:ticks 指令(有关 ticks 指令的更多信息,请参见下文)、encoding 指令(有关 encoding 指令的更多信息,请参见下文)和 strict_types 指令(有关类型声明页面的 严格类型 部分的更多信息,请参见)

由于指令是在编译文件时处理的,因此只能使用字面量作为指令值。不能使用变量和常量。举例说明

<?php
// 这有效:
declare(ticks=1);

// 这无效:
const TICK_VALUE = 1;
declare(
ticks=TICK_VALUE);
?>

declare 块的 statement 部分将被执行 - 如何执行以及执行期间会发生什么副作用可能取决于 directive 块中设置的指令。

declare 结构也可以在全局范围内使用,影响它之后的所有代码(但是,如果包含了包含 declare 的文件,则它不会影响父文件)。

<?php
// 这些是一样的:

// 你可以使用这个:
declare(ticks=1) {
// 整个脚本在这里
}

// 或者你可以使用这个:
declare(ticks=1);
// 整个脚本在这里
?>

滴答

滴答是一个事件,它在 declare 块中解析器执行的每个 N 个低级可滴答语句时发生。 N 的值使用 ticks=Ndeclare 块的 directive 部分中指定。

并非所有语句都可滴答。通常,条件表达式和参数表达式不可滴答。

每次滴答发生的事件使用 register_tick_function() 指定。有关更多详细信息,请参见下面的示例。注意,每次滴答可以发生多个事件。

示例 #1 滴答使用示例

<?php

declare(ticks=1);

// 在每个滴答事件上调用的函数
function tick_handler()
{
echo
"tick_handler() called\n";
}

register_tick_function('tick_handler'); // 导致滴答事件

$a = 1; // 导致滴答事件

if ($a > 0) {
$a += 2; // 导致滴答事件
print $a; // 导致滴答事件
}

?>

另见 register_tick_function()unregister_tick_function().

编码

可以使用 encoding 指令为每个脚本指定脚本的编码。

示例 #2 为脚本声明编码。

<?php
declare(encoding='ISO-8859-1');
// 这里的代码
?>

注意

当与命名空间结合使用时,declare 的唯一合法语法是 declare(encoding='...');,其中 ... 是编码值。 declare(encoding='...') {} 当与命名空间结合使用时会导致解析错误。

另见 zend.script_encoding.

添加注释

用户贡献的注释 10 个注释

65
匿名
13 年前
令人惊奇的是,有多少人没有理解这里的概念。请注意文档中的措辞。它指出,滴答处理程序在每个 n 个本机执行周期被调用。这意味着本机指令,不包括系统调用(我猜)。这可以让你很好地了解是否需要优化脚本的特定部分,因为你可以相当有效地测量实际代码中的本机指令数量。

一个好的分析器会考虑到这一点,并强迫你,开发人员,在进入和离开每个函数时包含对分析器的调用。这样你就可以监控每个函数完成需要多少个周期。独立于时间。

这非常强大,不容低估。一个好的解决方案将允许汇总统计信息,以便统计函数中的总时间,包括在被调用函数内部的时间。
22
Kubo2
9 年前
请注意,在 PHP 7 中 <?php declare(encoding='...'); ?> 如果 Zend 多字节被关闭,则会抛出 E_WARNING。
22
sawyerrken at gmail dot com
11 年前
在以下示例中

<?php
function handler(){
print
"hello <br />";
}

register_tick_function("handler");

declare(
ticks = 1){
$b = 2;
}
//closing curly bracket tickable
?>

"Hello" 将显示两次,因为右括号也是可滴答的。

人们可能会奇怪,为什么左括号不可滴答,而右括号可滴答。这是因为 PHP 开始滴答的指令是由左括号给出的,因此滴答在它之后立即开始。
5
digitalaudiorock at gmail dot com
5 年前
关于我之前关于 declare(ticks=1) 在 5.6 和 7.x 之间的范围变化的评论,我想提到另一个关于它对信号处理程序的影响的例子

如果你的脚本使用 declare(ticks=1) 并分配处理程序,在 5.6 中,信号将被捕获并调用处理程序,即使运行的代码在包含的文件中(包含的文件没有声明)。但是,在 7.x 中,信号不会被捕获,直到代码返回主脚本。

对此的最佳解决方案是在可用时使用 pcntl_async_signals(true),这将允许信号在代码位于任何文件中时被捕获。
9
digitalaudiorock at gmail dot com
5 年前
对于任何与信号处理程序一起使用它的人来说,有一些重要事项需要注意。

如果有人尝试在可用时使用 pcntl_async_signals()(PHP >= 7.1)或在旧版本中使用 ticks,这是不可能的...至少不是以不为较新 PHP 版本启用 ticks 的方式。这是因为根本没有办法有条件地声明 ticks。例如,以下代码将“工作”,但并非以您期望的方式。

<?php
if (function_exists('pcntl_async_signals')) {
pcntl_async_signals(true);
} else {
declare(
ticks=1);
}
?>

虽然信号处理程序将与旧版本和新版本的代码一起工作,但即使在 pcntl_async_signals 存在的情况下,ticks 也会被启用,仅仅因为 declare 语句的存在。所以上面的代码在功能上等同于:

<?php
if (function_exists('pcntl_async_signals')) pcntl_async_signals(true);
declare(
ticks=1);
?>

另一件需要注意的是,这个声明的作用域从 PHP 5.6 到 7.x 有点变化...实际上,它似乎被纠正了,正如这里所述:

https://php.net/manual/en/function.register-tick-function.php#121204

这会导致一些非常令人困惑的行为。一个例子是 pear/System_Daemon 模块。在 PHP 5.6 中,即使使用它的脚本本身没有使用 declare(ticks=1),但它仍然可以与 SIGTERM 处理程序一起工作,但在 PHP 7 中,除非脚本本身具有该声明,否则它将无法工作。不仅处理程序不会被调用,而且信号也不会执行任何操作,并且脚本不会退出。

关于 ticks 的一个让我困扰已久的小插曲:似乎围绕这一切已经没有足够的困惑,互联网上充斥着关于 ticks 已被弃用并即将被移除的错误传言,我相信它们都是从这里开始的:

http://www.hackingwithphp.com/4/21/0/the-declare-function-and-ticks

尽管在页面末尾有一个非常不起眼的作者说明说他错了(即使是我也刚刚注意到),但文章的第一句非常突出的句子仍然这么说,而且那个页面几乎在任何 Google 搜索结果的顶部。
7
php dot net at e-z dot name
10 年前
你可以注册多个 tick 函数。

<?PHP
function a() { echo "a\n"; }
function
b() { echo "b\n"; }

register_tick_function('a');
register_tick_function('b');
register_tick_function('b');
register_tick_function('b');

?>

将在每次 tick 时输出
a
b
b
b
5
ja2016 at wir dot pl
6 年前
不要使用带有 BOM 的 uft-8 编码。然后,致命错误总是会发生。用不带 BOM 的 utf-8 替换它。

---

*BOM*
<?php
declare(strict_types=1);
//Fatal error: strict_types declaration must be the very first statement in the script
5
fok at nho dot com dot br
21 年前
这是一个使用 ticks 执行外部脚本以显示服务器的 rx/tx 数据的非常简单的示例。

<?php

function traf(){
passthru( './traf.sh' );
echo
"<br />\n";
flush(); // keeps it flowing to the browser...
sleep( 1 );
}

register_tick_function( "traf" );

declare(
ticks=1 ){
while(
true ){} // to keep it running...
}

?>

traf.sh 的内容
# 显示 eth0 的 TX/RX 数据,间隔 1 秒。
#!/bin/bash

TX1=`cat /proc/net/dev | grep "eth0" | cut -d: -f2 | awk '{print $9}'`
RX1=`cat /proc/net/dev | grep "eth0" | cut -d: -f2 | awk '{print $1}'`
sleep 1
TX2=`cat /proc/net/dev | grep "eth0" | cut -d: -f2 | awk '{print $9}'`
RX2=`cat /proc/net/dev | grep "eth0" | cut -d: -f2 | awk '{print $1}'`

echo -e "TX: $[ $TX2 - $TX1 ] bytes/s \t RX: $[ $RX2 - $RX1 ] bytes/s"
#--= 结束。 =--
4
markandrewslade at dontspamemeat dot gmail
15 年前
注意,调用 declare 的两种方法并不完全相同。

方法 1

<?php
// 使用时间戳和可选后缀打印 "tick"。
function do_tick($str = '') {
list(
$sec, $usec) = explode(' ', microtime());
printf("[%.4f] Tick.%s\n", $sec + $usec, $str);
}
register_tick_function('do_tick');

// 在声明之前 tick 一次,以便我们有一个参考点。
do_tick('--start--');

// 方法 1
declare(ticks=1);
while(
1) sleep(1);

/* 输出:
[1234544435.7160] Tick.--start--
[1234544435.7161] Tick.
[1234544435.7162] Tick.
[1234544436.7163] Tick.
[1234544437.7166] Tick.
*/

?>

方法 2
<?php
// 使用时间戳和可选后缀打印 "tick"。
function do_tick($str = '') {
list(
$sec, $usec) = explode(' ', microtime());
printf("[%.4f] Tick.%s\n", $sec + $usec, $str);
}
register_tick_function('do_tick');

// 在声明之前 tick 一次,以便我们有一个参考点。
do_tick('--start--');

// 方法 2
declare(ticks=1) {
while(
1) sleep(1);
}

/* 输出:
[1234544471.6486] Tick.--start--
[1234544472.6489] Tick.
[1234544473.6490] Tick.
[1234544474.6492] Tick.
[1234544475.6493] Tick.
*/
?>

请注意,当在 declare 后使用 {} 时,do_tick 直到我们进入 declare {} 块大约 1 秒后才被自动调用。但是,当不使用 {} 时,do_tick 在调用 declare(); 后不仅被自动调用了一次,而是被调用了两次。

我假设这是由于 PHP 处理 tick 的内部机制造成的。也就是说,没有 {} 的 declare() 似乎会触发更多低级指令,从而在声明的过程中多次触发 tick(如果 ticks=1)。
1
ohcc at 163 dot com
4 年前
如果每个指令都受支持,可以一次设置多个指令。
<?php
declare(strict_types=1, encoding='UTF-8');
?>
To Top