DEV Community

[Comment from a deleted post]
Collapse
 
slifin profile image
Adrian Smith • Edited

PHP Object History

If you asked Alan Kay co-creator of smalltalk and populariser of Object Orientated Programming, what is important in OOP, he would tell you messaging and late binding, he would give you the example of the internet, the human cell.

With the internet the individual does not matter, but the messaging matters, the messaging protocol keeps the internet alive gives all the objects a common ground, late binding allows behaviour to pass through many individuals.

Please have a read of medium.com/skyfishtech/retracing-o...

or if you need a tl;dr this is a quote from his wiki: I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea. The big idea is "messaging"

What you are describing here is class orientated programming. COP? Anyway briefly some more history, PHP survived 10 years without classes and then under pressure imo of Java and other languages they were implemented with some horrible semantics, you've picked up on the first one:

  • Change by reference by default
  • Horrible to work out where a property may have been set (even with a single setter + private it can be changed anywhere in object lifecycle)
  • Magic keyword $this (at least python requires it as a parameter)
  • private/protected/public
  • traditional singular inheritance

SOLID as an acronym seems to have picked up mainstream support around 2015, I see references to it from 2009 the popularisation of it was done by Michael Feathers, as part of the agile movement, Michael's claim to fame seems to be being involved with the agile movement via his linkedin he is currently: "I'm helping teams and pursuing research in business / development communication, preventing errors through design practice and array-functional programming languages" emphasis mine.

He changed his focus away from objects? But where did the ideas come from? Well they come much earlier in 2003 from Robert Cecil Martin, co-author of the agile manifesto they used to be called "the first five principles" from here: butunclebob.com/ArticleS.UncleBob...., Robert is a consultant who sells videos and books and co-authored the agile manifesto..

So to recap modern OOP is a Chinese whispers of the original ideas in small talk and SOLID came out 40-50 years after OOP and I'm assuming was created by people needing substance for their agile manifesto and contracting services, books, videos? And I don't mean to question their intent I think they want to have better code, but I doubt they found fundamental truths that will mean clean code forever 40 years later

SOLID as a concept it's certainly better than what we had, but I don't think class orientated programming was up to much either, in my opinion it distracts from what the important things in programming are, is there something else we can do?

Problems with defensive programming

Don't trust developers

Why are we not trusting developers? I wonder if this came about because as developers we often hate ourselves because we're told we're wrong 100s of times a day by our code?

Anyway if we truly believed this we would never use a function from another developer because we can't trust them, I often see this sentiment as explanation for why we should be setting everything to private.

So what does setting everything to private accomplish? Well it blocks the callee of the object from doing something with the object, by setting something to private we are saying, I know better than you, the callee, particularly what you want from this object, and I won't let you pass.

Let's ignore the fact that the callee often knows exactly what they want and can be trusted in that regard, the assertion that the callee cannot get access is also bunk, even at runtime, which I'll explain shortly:

Don't leak state outside class scope

Whether a property is changed via an internal setter or external property it makes no difference

Those properties can be changed in both inside and outside the object anyway (although many "OOP" developers believe that to not be the case).

PHP objects change by reference which makes for some horrible debugging scenarios because it's not obvious where the change occurred

From what I remember PHP has object change by reference by default for memory usage reasons those restrictions certainly don't feel very valid today but maybe objects still do suck when it comes to memory usage?

Create immutable objects

I hate that the COP community have taken immutability a largely functional concept and then claimed it's possible in PHP objects, the only immutable things in PHP are constants and DateTimeImmutable, and that's only because DateTimeImmutable can't be injected from userland afiak let's demostrate how to break these weak assumptions:

class TrustNoOne {
    private $data = 'SAD';
}

$sad_object = new TrustNoOne();

$happy_object = make_data_happy($sad_object);

function make_data_happy(TrustNoOne $object) : TrustNoOne {
    return (function () : TrustNoOne {
        $this->data = 'Happy';
        return $this;
    })->call($object);
}

Thanks to PHP Closures the callee can extract or change what it needs from the object, setters and private scope are NOT immutable, and thank god this is the case because there are situations where you cannot edit the original class, particularly if it's third party code, the object developer isn't the best judge of how the object should be used because they can't possibly know all future requirements, but the callee should have more context about the problem space, it could be you for example, you need the data in the object but now you need it in a new context, but now everything is coupled in your old context.

Generally speaking future you is smarter than old you, trust future callees to your data, because you have no choice so make those "internal" methods well.

What are PHP objects good for?

Due to the overwhelming popularity of OOP, autoloading in PHP requires the use of classes, objects seemed like a good grouping mechanism but now that we have namespaces that's not particularly true any more but autoloading hasn't been updated, most autoloaders will still allow include based imports but it could be nicer.

There's always the argument to be had that if your project uses OOP (maybe you use Laravel) then you should too for consistency, If you are doing that, I would suggest the following, never use $this, never use extend, familiarise yourself deeply with closures to create functional interfaces to objects outside of your control, accept functions as parameters over dependency injection, do not loop without a function (unless for performance reasons)

If you can, try and use free functions in namespaces over free functions disguised inside objects as methods because it removes the redundancy (and old temptations) but this may not be possible if you're forced to be consistent with what COP is there already.

Problems in maintaince

COP developers are too caught up in their abstractions and syntax, to give much thought to proper naming of things, or doing anything but procedural code in their methods

i.imgur.com/mh3P7CD.png

As a result debugging, upgrading, or deleting COP code is a nightmare because often the code's names is too caught up talking about the abstraction to remember the problem domain, but even at the low levels the attitude of skipping problem specific names is pervasive.

how many times have you seen code like this?

foreach ($data as $item) {
  if ($item['age'] > 4) {
    $allowed[] = $item;
  }
}

let me demonstrate what this code functionally does:

foreach ($data as $items) {
    $outer_symbols = get_defined_vars();
    $inner_vars = (function ($outer_symbols) {
        if ($outer_symbols['item']['age'] > 4) {
            $symbols = get_defined_vars();
            (function ($symbols) {
                $symbols['allowed'][] = $symbols['item'];
            })($symbols);
            extract($symbols);
        }
        return $outer_symbols;
    })($outer_symbols);
    extract($inner_vars);
}

If a functional programmer gave me the above code at code review I'd ask some very personal prying questions about their drug use.

My point is that the if statement in the block and foreach block invisibly import everything from the outer scope in, without describing what is going to be used or what type those variables are or what the operation is in the first place.

If the hardest thing in programming is naming things we can do better:

function is_old_enough_to_ride_merry_go_round(array $person) : bool {
    $is_old_enough = $person['age'] > 4;
    return $is_old_enough;
}

$merry_go_round_people = array_filter($people, 'is_old_enough_to_ride_merry_go_round');

What's the intention of the code above? Now that we've added a function name, some variable names, some type hints, the code is suddenly much easier to understand from the point of view it tells us what it intends to do

It's longer sure, it requires the knowledge of a how an inbuilt PHP function works, but it contains something the other two implementations do not, it contains code intent.

As a maintainer I don't give a rats ass about your code implementation if I already know your code intent, but so often I have to reverse engineer it from your implementation, and let's both hope you left enough implementation clues for me to get that process right, if not I'm going to "fix" your code with faulty assumptions.

That's not a trust issue that's a you didn't tell me jack in your code problem.

In the first implementation it's not written right there in English, Do not code defensively, code clearly with intent or don't write it at all.

So to conclude learn how to use these functions semantically:

  • array_map - change array children
  • array_filter - remove array children
  • array_reduce - aggregate over array children
  • array_walk - iterate with side effects over children
  • usort (SQL sorting is better usually) - sort children

Name your intent, use arrays for data (change by copy by default, interop with above functions) use variable names for context

Use boolean logic that outputs variable names, over inline if statements, use small functions, if you're nesting code blocks with control statements you're doing it wrong, if you have problems with the iteration functions above read the last example on this page: phptherightway.com/pages/Functiona...

Remember to use your common sense when applying these rules and if you need (or anyone needs) more explanation on the above or how PHP is an amazing language for functional code then please reach out twitter.com/sfyire