PHP Never Made Me Wait For Anything. Then I Met Python’s Claude API Examples.

PHP has a function literally called die(). Not a metaphor, not slang — an actual keyword sitting right there in the language. Ask it something, it answers immediately, or the whole script keels over on the spot. Dramatic, but honest: that’s basically the whole personality of the language I spent seven years in.

Then I opened the Claude API docs, and every example is wearing decorators — sometimes two or three stacked on the same function, like it packed for a trip it wasn’t sure the length of. Each one just sits there, quietly holding your lukewarm soy, sugar-free, [taste-free] caramel macchiato — the one you ordered on the way in, have been carrying for the last thirty minutes while telling a coworker about anything except the actual work, and which is no longer “hot” by any legal definition of the word. It’s just… present. Warm-ish. Present.

Here’s the block, close to what actually shows up in Claude API streaming examples, with the greatest hits assembled in one place:

@app.post("/chat")
@retry(max_attempts=3)
async def stream_response(payload: ChatRequest) -> AsyncGenerator[str, None]:
    async with client.messages.stream(
        model="claude-sonnet-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": payload.prompt}],
    ) as stream:
        async for chunk in stream.text_stream:
            if (chunk := chunk.strip()) is not None:
                yield chunk

If you came up through Exercism or HackerRank Python, this probably looks reasonable, maybe even tidy. If you came up through PHP, this looks like a ransom note assembled from five different alphabets. @app.post, @retry, async, await (waiting in the wings even where it’s not printed), as, yield, a ChatRequest type that’s secretly a whole Pydantic class you have to go find in another file, and a type hint — AsyncGenerator[str, None] — that reads less like a return type and more like Python narrating its own anxiety.

And then there’s the walrus operator, chunk := chunk.strip(), assigning a variable and judging its own output in the same breath, like it couldn’t be bothered to wait for two separate lines to make its point. I stared at that one for a genuinely embarrassing amount of time before I believed it was legal syntax and not a typo that somehow ran anyway.

chunk, for what it’s worth, might be the best-named variable in the entire language. One more nested decorator and I was fully prepared to rename the function blow_chunks() and let future-me sort out the fallout in code review.

I’ve done plenty of JavaScript — I know await. Your browser waits on the server. Fine, normal, the user clicked something, of course there’s a pause. Nobody warned me that in Claude’s Python examples, the server is the one doing the waiting. The thing that’s supposed to make everyone else wait is over here going await, patiently taking a number for its own turn, holding for Claude to finish thinking before it can hand anything back.

Since when does the server get a coffee break?

Here’s what I want to be clear about, because it’d be easy to read all of this as “I’m rusty.” I’m not. Seven years of PHP taught me how systems actually talk to each other — request lifecycles, state, what happens when something fails halfway through a call. That knowledge transfers completely, Claude API included. What doesn’t transfer automatically is which odd-looking punctuation Python currently prefers for saying “hang on, I’m thinking” while it’s mid-conversation with a model.

I’ve read something like 20,000 job listings over the last two and a half years chasing my next role. Half of them ask for “5+ years of experience” in a framework that’s been public for two. Nobody’s doing the arithmetic — it’s tenure used as a lazy stand-in for fluency, applied to syntax that hasn’t existed long enough to make the number mean anything.

So no. I haven’t gone rusty because a walrus operator made me stare at my screen for a full minute. I met five odd little words holding my lukewarm coffee while I figured out what they actually do. die() never asked this much of me. Then again, die() never streamed anything back word by word, either.