PHP Callback / Callable 类型 学习笔记

本文通过一个具体的PHP类实例,展示了如何使用回调函数和闭包。文章详细解释了如何定义类和对象,设置回调方法,并利用回调函数直接调用对象方法的过程。此外,还给出了一段静态方法作为回调函数的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实例:

class Test {
    protected $items = array();
    protected $obj;
    public function __construct()
    {
        $this->obj = new Obj();
        $this->items[] = array($this, 'callBackOne');
        $this->items[] = array($this, 'callBackTwo');
        $this->items[] = array($this->obj, 'callObjOne');
        $this->items[] = array($this->obj, 'callObjTwo');
    }

    public function callBackOne()
    {
        echo __METHOD__ . ' has been called as a callback.';
    }

    public function callBackTwo()
    {
        echo __METHOD__ . ' has been called as a callback.';
    }

    public function getItems()
    {
        return $this->items;
    }
}

class Obj{
    public function callObjOne(){
        echo __METHOD__ . ' has been called as a callback.';;
    }
    public function callObjTwo(){
        echo __METHOD__ . ' has been called as a callback.';;
    }
}

$o = new Test();
$itemLists = $o->getItems();

foreach ($itemLists as $itemList) {
    echo '<pre>';
    echo "==========++++++++++=============";
    print_r($itemList);
    print_r($itemList());
    echo '</pre><br>';
}
结果:
==========++++++++++=============Array
(
    [0] => Test Object
        (
            [items:protected] => Array
                (
                    [0] => Array
 *RECURSION*
                    [1] => Array
                        (
                            [0] => Test Object
 *RECURSION*
                            [1] => callBackTwo
                        )

                    [2] => Array
                        (
                            [0] => Obj Object
                                (
                                )

                            [1] => callObjOne
                        )

                    [3] => Array
                        (
                            [0] => Obj Object
                                (
                                )

                            [1] => callObjTwo
                        )

                )

            [obj:protected] => Obj Object
                (
                )

        )

    [1] => callBackOne
)
Test::callBackOne has been called as a callback.

==========++++++++++=============Array
(
    [0] => Test Object
        (
            [items:protected] => Array
                (
                    [0] => Array
                        (
                            [0] => Test Object
 *RECURSION*
                            [1] => callBackOne
                        )

                    [1] => Array
 *RECURSION*
                    [2] => Array
                        (
                            [0] => Obj Object
                                (
                                )

                            [1] => callObjOne
                        )

                    [3] => Array
                        (
                            [0] => Obj Object
                                (
                                )

                            [1] => callObjTwo
                        )

                )

            [obj:protected] => Obj Object
                (
                )

        )

    [1] => callBackTwo
)
Test::callBackTwo has been called as a callback.

==========++++++++++=============Array
(
    [0] => Obj Object
        (
        )

    [1] => callObjOne
)
Obj::callObjOne has been called as a callback.

==========++++++++++=============Array
(
    [0] => Obj Object
        (
        )

    [1] => callObjTwo
)
Obj::callObjTwo has been called as a callback.
综上示例:array($object,$object方法名)()可以直接调用$object方法中对应的方法


class Foo {
    public static function doAwesomeThings() {
        FunctionCaller::callIt(self::class . '::someAwesomeMethod');
    }

    public static function someAwesomeMethod() {
        echo "静态方法Callback/callable类型的调用";
    }
}

class FunctionCaller {
    public static function callIt(callable $func) {
        call_user_func($func);
    }
}

Foo::doAwesomeThings();
执行结果:静态方法Callback/callable类型的调用
为什么我转到定义的时候是这些#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) void (* Base_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Base Msp Init Callback / void ( Base_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Base Msp DeInit Callback / void ( IC_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM IC Msp Init Callback / void ( IC_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM IC Msp DeInit Callback / void ( OC_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM OC Msp Init Callback / void ( OC_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM OC Msp DeInit Callback / void ( PWM_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM PWM Msp Init Callback / void ( PWM_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM PWM Msp DeInit Callback / void ( OnePulse_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM One Pulse Msp Init Callback / void ( OnePulse_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM One Pulse Msp DeInit Callback / void ( Encoder_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Encoder Msp Init Callback / void ( Encoder_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Encoder Msp DeInit Callback / void ( HallSensor_MspInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Hall Sensor Msp Init Callback / void ( HallSensor_MspDeInitCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Hall Sensor Msp DeInit Callback / void ( PeriodElapsedCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Period Elapsed Callback / void ( PeriodElapsedHalfCpltCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Period Elapsed half complete Callback / void ( TriggerCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Trigger Callback / void ( TriggerHalfCpltCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Trigger half complete Callback / void ( IC_CaptureCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Input Capture Callback / void ( IC_CaptureHalfCpltCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Input Capture half complete Callback / void ( OC_DelayElapsedCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Output Compare Delay Elapsed Callback / void ( PWM_PulseFinishedCallback)(struct __TIM_HandleTypeDef htim); /!< TIM PWM Pulse Finished Callback / void ( PWM_PulseFinishedHalfCpltCallback)(struct __TIM_HandleTypeDef htim); /!< TIM PWM Pulse Finished half complete Callback / void ( ErrorCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Error Callback / void ( CommutationCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Commutation Callback / void ( CommutationHalfCpltCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Commutation half complete Callback / void ( BreakCallback)(struct __TIM_HandleTypeDef htim); /!< TIM Break Callback / void ( Break2Callback)(struct __TIM_HandleTypeDef htim); /!< TIM Break2 Callback / #endif / USE_HAL_TIM_REGISTER_CALLBACKS */ } TIM_HandleTypeDef;你这个结构体定义又是哪里的typedef struct { uint32_t Prescaler; // 预分频值(分频后决定计数频率) uint32_t CounterMode; // 计数模式(向上、向下、中央对齐) uint32_t Period; // 自动重装载值(ARR,决定计数周期) uint32_t ClockDivision; // 时钟分频(用于滤波) uint32_t RepetitionCounter; // 重复计数器(高级定时器专用) } TIM_Base_InitTypeDef;
最新发布
03-08
<think>嗯,用户问的是为什么在转到定义的时候看到了一大堆条件编译的代码,特别是#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)里面的那些回调函数指针。我需要先理解用户的问题背景。看起来用户在使用STM32的HAL库,可能是在查看TIM_HandleTypeDef结构体定义时遇到了条件编译的部分,里面有很多回调函数的指针,而用户可能对这部分代码的作用和存在原因不太清楚。 首先,我应该解释条件编译的作用。这里用的是USE_HAL_TIM_REGISTER_CALLBACKS这个宏,当它被定义为1时,才会包含那些回调函数指针。这说明HAL库提供了通过注册回调函数的方式来处理定时器的各种事件,比如定时器溢出、输入捕获等,而不是使用默认的中断处理函数。这样做的好处是让用户可以根据需要灵活地自定义回调,而不必修改库本身的代码。 接下来,用户还提到了另一个结构体TIM_Base_InitTypeDef,里面包含了预分频、计数模式等配置参数。我需要说明这两个结构体的不同用途。TIM_Base_InitTypeDef用于配置定时器的基本参数,比如时钟分频、计数模式等,属于硬件层面的配置。而TIM_HandleTypeDef中的回调函数指针则是软件层面的,用于事件处理,属于HAL库的中断处理机制的一部分。 用户可能不太清楚为什么需要这些回调函数,以及如何启用它们。可能需要进一步解释如何通过定义USE_HAL_TIM_REGISTER_CALLBACKS宏来启用回调注册功能,并且在使用时需要手动注册自己的回调函数,否则这些指针不会被初始化,导致无法使用回调功能。同时,应该提醒用户在使用前检查HAL库的文档或头文件,确认宏定义的位置和正确的使用方法。 另外,用户可能在实际开发中遇到问题,比如定义了宏但回调函数没有被调用,这时候需要检查宏是否正确定义,以及是否正确注册了回调函数。可能还需要提到HAL_TIM_RegisterCallback()这样的函数,用于将用户自定义的函数赋值给结构体中的函数指针。 最后,总结这两个结构体的关系:TIM_Base_InitTypeDef负责硬件配置,TIM_HandleTypeDef中的回调函数负责事件处理,两者共同完成定时器的初始化和功能实现。需要确保用户理解这两部分如何协同工作,以及条件编译在库代码中的灵活性和可配置性。</think>你在代码中看到的这种结构体定义属于STM32 HAL库的典型设计模式,主要用于实现定时器(TIM)的硬件抽象层控制。这里涉及两个关键结构体的定义: ### 一、条件编译的回调函数部分(TIM_HandleTypeDef) ```c #if (USE_HAL_TIM_REGISTER_CALLBACKS == 1) void (* Base_MspInitCallback)(...); // 基础硬件初始化回调 // ... 其他25个回调函数指针 #endif ``` #### 关键设计特点: 1. **条件编译**:通过 `USE_HAL_TIM_REGISTER_CALLBACKS` 宏控制是否启用回调机制 - 当定义 `USE_HAL_TIM_REGISTER_CALLBACKS=1` 时:开启回调函数支持 - 当为0或未定义时:使用传统的中断处理方式 2. **回调函数分类**: ```mermaid graph TD A[回调类型] --> B[硬件层回调] A --> C[功能模块回调] B --> MspInit B --> MspDeInit C --> 输入捕获(IC) C --> 输出比较(OC) C --> PWM生成 C --> 编码器接口 C --> 事件回调 ``` 3. **典型使用场景**: ```c // 用户自定义回调函数 void My_TIM_Callback(TIM_HandleTypeDef *htim) { // 处理定时器事件 } // 注册回调 HAL_TIM_RegisterCallback(&htim, HAL_TIM_PERIOD_ELAPSED_CB_ID, My_TIM_Callback); ``` ### 二、基础配置结构体(TIM_Base_InitTypeDef) ```c typedef struct { uint32_t Prescaler; // 预分频值,计算公式:f_cnt = f_ck_psc / (PSC + 1) uint32_t CounterMode; // 计数模式,支持: // TIM_COUNTERMODE_UP/DOWN/CENTERALIGNED1/2/3 uint32_t Period; // 自动重装载值ARR,决定定时周期 // 周期计算:T = (ARR+1)*(PSC+1)/TIMx_CLK uint32_t ClockDivision; // 时钟分频(用于数字滤波) uint32_t RepetitionCounter;// 重复计数(高级定时器TIM1/TIM8专用) } TIM_Base_InitTypeDef; ``` #### 配置示例: 假设使用72MHz时钟的定时器: ```c TIM_Base_InitTypeDef TIM_Config = { .Prescaler = 7199, // 7200分频 → 10KHz .CounterMode = TIM_COUNTERMODE_UP, .Period = 9999, // 10000次计数 → 1秒周期 .ClockDivision = TIM_CLOCKDIVISION_DIV1, .RepetitionCounter = 0 }; ``` ### 三、两者的关系 ```mermaid sequenceDiagram participant User participant HAL_Library participant TIM_HandleTypeDef participant TIM_Base_InitTypeDef User->>HAL_Library: 初始化定时器 HAL_Library->>TIM_Base_InitTypeDef: 配置硬件参数 HAL_Library->>TIM_HandleTypeDef: 关联基础配置 User->>TIM_HandleTypeDef: 注册回调函数(可选) TIM_HandleTypeDef->>HAL_Library: 触发中断事件 HAL_Library->>User_Callback: 调用注册的回调 ``` ### 四、使用建议 1. **回调机制选择**: - 需要灵活的事件处理 → 启用 `USE_HAL_TIM_REGISTER_CALLBACKS` - 简单应用 → 直接使用默认中断处理函数(如 `HAL_TIM_PeriodElapsedCallback()`) 2. **配置注意事项**: - 定时器频率计算公式: $$ f_{tim} = \frac{f_{clk}}{(Prescaler + 1) \times (Period + 1)} $$ - 高级定时器的重复计数器可实现更长的定时周期 3. **调试技巧**: ```c // 检查回调是否注册成功 if(htim->PeriodElapsedCallback != NULL) { // 回调已正确注册 } ``` 这些设计体现了STM32 HAL库的两个重要特点:硬件配置与事件处理的解耦、功能模块的可扩展性。理解这种结构对深入掌握STM32的中断处理和定时器应用非常重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值