Is it possible to use array_walk() to append terms to an array of posts?

I guess you have a problem with variable scopes in here.

        array_walk($terms, function(&$term, $term_index) {
            // die(print_r($term));
            if (isset($term->slug)) {
                array_push($post->terms, $term->slug);
            }
        });

In this part of your code, you use anonymous function and inside of it you use $post variable. But it is a different variable than the one from few lines back – you’re in different function now.

But you can simplify that code a lot:

$posts = get_posts($args);
array_walk($posts, function(&$post, $index) {
    $terms = wp_get_post_terms($post->ID, 'category');

    if ( ! empty($terms) && ! is_wp_error($terms) ) {
        $post->terms = [];

        foreach ($terms as $term) {
            $post->terms[] = $term->slug;
        }
    }
});

return $posts;

And even easier, if you know some “magic” WP functions like wp_list_pluck

$posts = get_posts($args);
array_walk($posts, function(&$post, $index) {
    $terms = wp_get_post_terms($post->ID, 'category');
    $post->terms = []; // Prevents error on blade template's implode()

    if ( ! empty($terms) && ! is_wp_error($terms) ) {
        $post->terms = wp_list_pluck( $terms, 'slug' );
    }
});

return $posts;

PS. You have some errors in your $args too.

    $args = [
        'posts_per_page' => -1,
        'post_type' => 'portfolio',
        'post_status' => 'publish',
        'order_by' => 'date',
        'order' => 'DESC',
    ];

It should be orderby instead of oder_by.