A child theme functions.php appends; it does not replace

Every other file in a child theme replaces its parent equivalent: drop in single.php and the parent’s is not loaded. functions.php is the exception — both are included, the child’s first — so redefining a parent function there is not an override, it is a fatal error on the second declaration.

// parent functions.php — the guard is what makes overriding possible at all
if ( ! function_exists( 'catalogue_footer_credit' ) ) {
    function catalogue_footer_credit() { /* ... */ }
}

// child functions.php — loaded first, so this one wins and the parent declines
function catalogue_footer_credit() { /* ... */ }

// for something the parent hooked, unhook after the parent has hooked it
add_action( 'after_setup_theme', function () {
    remove_action( 'wp_footer', 'catalogue_analytics', 20 );
} );

The load order is what makes the function_exists() pattern work, and it also means a parent that does not use the guard cannot be overridden this way at all — the only lever left is the hook system. remove_action() needs the identical callback and the identical priority, and it has to run after the add_action() it is undoing, which is why it goes inside after_setup_theme or init rather than at the top of the file. A closure the parent passed to add_action() cannot be removed at all, since there is no reference to name. The other half people get wrong in a child theme is the stylesheet: @import in style.css is a second blocking request the browser cannot discover until the first one has parsed, so enqueue the parent sheet and declare the child’s as depending on it.