调用栈(call stack)

一叠便条:插入的待办事项放在清单的最前面;读取待办事项时,你只读取最上面的那个,并将其删除。因此这个待办事项清单只有两种操作**:压入**(插入)和弹出(删除并读取)。

image-20211019180002253

这种数据结构称为。栈是一种简单的数据结构,刚才我们一直在使用它,却没有意识到!

函数演示

计算机在内部使用被称为调用栈的栈。我们来看看计算机是如何使用调用栈的。下面是一个简单的函数。

<?php
function greet($name) {
    echo "hello ".$name;
    greet2($name);
    echo "go to ready bye...";
    bye();
}

function greet2($name) {
    echo "how are you" . $name;
}

function bye() {
    echo "ok bye";
}

栈调用分析

假设你调用greet("maggie"),计算机将首先为该函数调用分配一块内存。

image-20211019180602832

我们来使用这些内存。变量name被设置为maggie,这需要存储到内存中。

image-20211019180625189

每当你调用函数时,计算机都像这样将函数调用涉及的所有变量的值存储到内存中。接下来,你打印hello maggie!,再调用greet2("maggie")。同样,计算机也为这个函数调用分配一块内存。

image-20211019180643255

计算机使用一个栈来表示这些内存块,其中第二个内存块位于第一个内存块上面。你打印how are you, maggie?,然后从函数调用返回。此时,栈顶的内存块被弹出。

image-20211019180717540

现在,栈顶的内存块是函数greet的,这意味着你返回到了函数greet。当你调用函数greet2时,函数greet只执行了一部分。这是本节的一个重要概念:调用另一个函数时,当前函数暂停并处于未完成状态。该函数的所有变量的值都还在内存中。执行完函数greet2后,你回到函数greet,并从离开的地方开始接着往下执行:首先打印getting ready to say bye…,再调用函数bye

image-20211019180808604

在栈顶添加了函数bye的内存块。然后,你打印ok bye!,并从这个函数返回。

image-20211019180833098

现在你又回到了函数greet。由于没有别的事情要做,你就从函数greet返回。这个栈用于存储多个函数的变量,被称为调用栈

递归调用栈

递归函数也使用调用栈!来看看递归函数factorial的调用栈。factorial(5)写作5!,其定义如下:5! = 5 * 4 * 3 * 2 * 1。同理,factorial(3)3 * 2 * 1。下面是计算阶乘的递归函数。

<?php
function fact($x) {
    if($x == 1) {
        return 1;
    } else {
        return $x * fact($x-1 );
    }
}