What Years of PHP Taught Me About Python
I spent the first week wondering why my Python functions kept returning None. I'd been writing PHP for nine years.
This isn't a "PHP vs Python" post. I still respect PHP. Laravel is still excellent. This is about what the transition taught me -- things I couldn't have seen from inside one ecosystem.
What Made Me Look at Python
I'll keep this brief.
The PHP/Laravel job market is competitive and narrowing. That's not a knock on the language -- it's a market reality that any honest senior PHP developer will recognize. AI and ML tooling is Python-native. If you want to work in that space, Python is the path.
I built a Python automation tool and realized I actually enjoyed it. The goal wasn't to abandon PHP -- it was to add range.
What Transferred Immediately
These are the things PHP prepared me for better than I expected.
Mental models for web backends. Request/response lifecycle, middleware, dependency injection -- the concepts are identical. Laravel's service container maps almost directly to FastAPI's Depends(). Writing a route handler in FastAPI felt immediately familiar.
Database thinking. Years of Eloquent ORM made SQLAlchemy feel readable almost immediately. Migration mindset -- never touch the DB manually, always migrate -- transferred perfectly. Query optimization instincts translate directly. N+1 problems look the same in any ORM.
Queue and worker patterns. Laravel Horizon to ARQ is a conceptual one-to-one. Job idempotency, retry logic, dead letter queues -- same problems, different syntax. Redis as a queue backend: identical.
Testing discipline. PHPUnit to Pytest is a smaller jump than expected. The habit of writing tests at all is the hard part, and that habit was already built. Fixtures in Pytest are more powerful than Laravel factories in interesting ways -- I found myself wishing I'd had them in PHP.
API design instincts. REST conventions, status codes, error envelopes -- all language-agnostic. Years of reading Stripe's API design made FastAPI's decorator style feel natural.
What Genuinely Surprised Me
Whitespace as syntax takes longer to internalize than you think. You know indentation matters in Python. You'll still spend 20 minutes debugging an indentation error in week two. PHP's curly braces felt like training wheels I didn't know I was wearing. The surprising upside: whitespace enforcement forces a consistency that PHP codebases rarely have organically.
Python's import system is weird coming from Composer. from app.core.config import settings versus Laravel's autowiring felt verbose at first. Virtual environments (venv) are a context switch from Composer's project-local approach. Once it clicks, it's fine -- but it takes a week to click.
Type hints are optional, which is a trap. PHP 7+ pushed me toward type declarations. Python lets you skip them entirely. The temptation to skip types "just for now" is real, and it leads to unmaintainable code fast. My advice: treat type hints as mandatory from day one, even though Python won't force you to.
None is not null in exactly the way you think it is. My first real Python bug came from assuming a function would return something implicitly -- in PHP, a function without an explicit return gives you null, and you learn to check for it. In Python, every function without a return statement gives you None, but the patterns around checking for it are subtly different. PHP's loose comparison (== vs ===) trains habits that backfire in Python, where is None is the convention and == None is a code smell.
Async is a first-class concern, not an afterthought. PHP is synchronous by default. Async is bolted on -- Swoole, ReactPHP. Python's async/await is woven into the standard library and ecosystem. FastAPI is async-native. You can't half-commit to it the way you might with PHP async. This required a genuine mental model shift, not just syntax learning.
What I Had to Actively Unlearn
These are the PHP habits that caused real problems in Python.
Mutable default arguments
The classic Python gotcha that every PHP developer hits.
# This is a bug -- the list is shared across all calls
def add_item(item, items=[]):
items.append(item)
return items
In PHP, default parameter values are re-evaluated each call. In Python, they're evaluated once at function definition time. The list is created once and mutated forever. The fix:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
This one will get you. It got me.
String interpolation habits
PHP's "Hello $name" embeds variables naturally. Python f-strings (f"Hello {name}") are actually better -- more expressive, more capable. But the muscle memory takes time. The subtle trap: forgetting the f prefix and getting a literal string with curly braces. You'll stare at "Hello {name}" in your output for longer than you'd like to admit before you spot it.
Array thinking vs list/dict thinking
PHP arrays are everything -- ordered maps, lists, stacks, queues. Python separates these concerns: list, dict, tuple, set, each with distinct semantics. Learning to reach for the right data structure instead of defaulting to "array" made my code meaningfully cleaner. But the first week, everything was a list because that's the closest thing to what I knew.
Magic methods and facades
Laravel facades train you to reach for static-feeling APIs everywhere. Python doesn't have this pattern -- explicit dependency passing is the norm. This is actually better architecture, but it felt verbose at first. The transition from Cache::get('key') to passing a cache dependency explicitly made me realize how much magic I'd been relying on without thinking about it.
What Python Does Genuinely Better
I'm being fair and specific here. Not generic "Python is great" talking points.
The REPL and iterative exploration. python -m asyncio for async exploration beats php artisan tinker in several ways. The ability to just drop into a Python shell and test an idea in seconds -- without booting a framework -- changed how I prototype.
The data science and AI ecosystem. There's no PHP equivalent. Period. NumPy, pandas, scikit-learn, PyTorch -- if this is the direction your career is heading, Python is the only serious option.
Concurrency model. async/await in Python feels more coherent than anything in PHP's ecosystem. It's built in, well-documented, and the community has converged on patterns that work.
Readability enforcement. The whitespace thing I resisted in week one genuinely produces more consistent codebases in teams. When you can't argue about brace placement, you argue about things that matter instead.
What PHP/Laravel Still Does Better
This section is what makes this post honest. I'm not going to skip it.
Laravel is still the best full-stack web framework in any language for certain use cases. That's a defensible position, and I'll stand by it. Eloquent's expressiveness for rapid CRUD development has no Python equivalent that's as polished. Laravel Nova, Livewire, the first-party ecosystem -- Python has nothing as cohesive.
The PHP community's investment in developer experience is genuinely impressive. Tinker, Telescope, Horizon UI -- these tools reflect a community that cares about the day-to-day experience of building software, not just the software itself.
For agencies building client sites and SaaS products rapidly, Laravel is still often the right tool. I wouldn't tell a Laravel shop to rewrite in Python. That would be bad advice.
Honest Advice for PHP Developers Considering Python
Don't try to learn Python in the abstract. Build something specific. I built an automation tool, and having a real problem to solve made the learning stick in ways that tutorials never could.
Map concepts to Laravel equivalents as you go. It accelerates learning dramatically. When I thought of FastAPI's Depends() as "service container injection," it clicked immediately.
Commit to type hints from day one. Optional typing is a false economy. You'll thank yourself in month two when you're reading code you wrote in week one.
The transition is easier than you think and harder than you think -- in different places. The web concepts transfer cleanly. The ecosystem differences take real adjustment. The syntax is a weekend. The mental models take a month.
You don't have to abandon PHP. Bilingual engineers are more valuable, not less. I'm still writing Laravel. I'm also writing Python. The two make me better at each.