Is the global state believed to be evil because of its nature or mostly due to its usual, no-rules usage?
I don't dislike global state, but that could be due to the lack of experience. I was thinking about what the usual implementation of global state is: A big variable where data flows in a non-consistent, unpredictable but most importantly, non-standardized way, referring to all CRUD operations. An implementation like global $steps; where you would always do global $steps; $steps['insert']['key_name']['and_value']; to get a value is, in my opinion, why global state is hated and I believe, partially, because people have become a bit too accommodated to objects and for no good reason. I'll try to naively show how to try to overcome these in order to aid my question. The problem with just polluting the global state with all kinds of data inside of a variable is that that this way has absolutely not consistent ways to perform CRUD, nor it has rules. Anything can happen, where as objects must respect interfaces, return types and so on, a variable can be...anything. It's extremely hard to predict what goes in and out, or worse yet, in what form. But what if that global state was accessed in very well-thought, documented & clear ways, so that it's always predictable? Take my cache object example, that serves as a temporary cache, per PHP request: class Cache { /** * Holds all of our data in a key=>value manner. * * @var array */ private $data; /** * Adds data to a key. * * @param string $key The key, used as an identifier. * @param mixed $data The data that we're adding to that identifier. */ public function addData( $key, $data ) { //Should perform integrity checks, etc. $this->data[$key][] = $data; } /** * Retrieves data based on a key. * * @param string $key The key, used as an identifier. * @return mixed */ public function getData( $key ) { return $this->data[$key]; } /** * Changes data, where data is the value of a key in the big array. * * @param string $key The key, used as an identifier. * @return void */ public function changeData( $key ) { if( checkIntegrityAndOtherStuff( $this->data[$key] ) ) { $this->data[$key] = $data; return True; } //If we failed our checks return False; } } It's a very minimal implementation, but, assuming we had strong checks & rules in place (I will come back to this extremely vital point which I think could be the Achilles' hill of it all in a bit), then we have a predictable system that we can refer to: global $cache = new Cache; that we can always rely on to work in just one specific way and nothing else: $cache->addData( 'user_list', [['name' => 'John'], ['name' => 'Jen']] ); $cache->getData( 'user_list' ); We have all the clear signs of good implementation: good naming, predictability, testability, it's concise, but most importantly, easy to use. So what is wrong here? The possible Achilles' heel.The one thing that defeats it all could be the fact that you cannot impose any type of contract / pattern on the data being added to these keys, unlike objects where you can set return types / interfaces and know what to expect when you retrieve something, here, you can't, the developer must know beforehand what he's getting, otherwise he's in the dark, with the other, worse side to it that anyone, even if well-intended can change the data contents (and therefore structure) without any consequences, rendering code that relies on it unusable. If we had things such as "data contracts" that would be bound & required to the data we add (for retrieval later on), then no one could nor add the wrong data type / structure, nor retrieve it, creating a perfectly predictable, well-structured & ruly environment that everyone can benefit from and access. It might look something like this: public function addData( $key, $data, DataScheme $data_scheme ) { $structure = $data_scheme->getStructure(); if( dataDoesNotRespectScheme( $data, $data_scheme ) ) { //Break, do not allow it. } $this->data[$key][] = ['data' => $data, 'scheme' => $data_scheme]; } public function changeData( $key, $new_data ) { if( dataDoesNotRespectScheme( $this->data[$key]['scheme'], $new_data ) ) { //Fail. } else { //Add the new data which is 100% identical in scheme to the old one. } //If we failed our checks return False; } As such, the developer only has to know about the data structure, but he's 100% guaranteed to get it, in essence, creating a data interface which means that no matter what, code relying on retrieving this saved cannot fail. Is this what the global state must overcome to be accepted? If not, what would be a better solution to this or is the original intent of "I want to access data everywhere" a bad way of doing things?

I don't dislike global state, but that could be due to the lack of experience. I was thinking about what the usual implementation of global state is:
A big variable where data flows in a non-consistent, unpredictable but most importantly, non-standardized way, referring to all CRUD operations.
An implementation like global $steps;
where you would always do global $steps; $steps['insert']['key_name']['and_value'];
to get a value is, in my opinion, why global state is hated and I believe, partially, because people have become a bit too accommodated to objects and for no good reason.
I'll try to naively show how to try to overcome these in order to aid my question.
The problem with just polluting the global state with all kinds of data inside of a variable is that that this way has absolutely not consistent ways to perform CRUD, nor it has rules. Anything can happen, where as objects must respect interfaces, return types and so on, a variable can be...anything. It's extremely hard to predict what goes in and out, or worse yet, in what form.
But what if that global state was accessed in very well-thought, documented & clear ways, so that it's always predictable?
Take my cache object example, that serves as a temporary cache, per PHP request:
class Cache
{
/**
* Holds all of our data in a key=>value manner.
*
* @var array
*/
private $data;
/**
* Adds data to a key.
*
* @param string $key The key, used as an identifier.
* @param mixed $data The data that we're adding to that identifier.
*/
public function addData( $key, $data )
{
//Should perform integrity checks, etc.
$this->data[$key][] = $data;
}
/**
* Retrieves data based on a key.
*
* @param string $key The key, used as an identifier.
* @return mixed
*/
public function getData( $key )
{
return $this->data[$key];
}
/**
* Changes data, where data is the value of a key in the big array.
*
* @param string $key The key, used as an identifier.
* @return void
*/
public function changeData( $key )
{
if( checkIntegrityAndOtherStuff( $this->data[$key] ) ) {
$this->data[$key] = $data;
return True;
}
//If we failed our checks
return False;
}
}
It's a very minimal implementation, but, assuming we had strong checks & rules in place (I will come back to this extremely vital point which I think could be the Achilles' hill of it all in a bit), then we have a predictable system that we can refer to:
global $cache = new Cache;
that we can always rely on to work in just one specific way and nothing else:
$cache->addData( 'user_list', [['name' => 'John'], ['name' => 'Jen']] );
$cache->getData( 'user_list' );
We have all the clear signs of good implementation: good naming, predictability, testability, it's concise, but most importantly, easy to use.
So what is wrong here?
The possible Achilles' heel.The one thing that defeats it all could be the fact that you cannot impose any type of contract / pattern on the data being added to these keys, unlike objects where you can set return types / interfaces and know what to expect when you retrieve something, here, you can't, the developer must know beforehand what he's getting, otherwise he's in the dark, with the other, worse side to it that anyone, even if well-intended can change the data contents (and therefore structure) without any consequences, rendering code that relies on it unusable.
If we had things such as "data contracts" that would be bound & required to the data we add (for retrieval later on), then no one could nor add the wrong data type / structure, nor retrieve it, creating a perfectly predictable, well-structured & ruly environment that everyone can benefit from and access.
It might look something like this:
public function addData( $key, $data, DataScheme $data_scheme )
{
$structure = $data_scheme->getStructure();
if( dataDoesNotRespectScheme( $data, $data_scheme ) ) {
//Break, do not allow it.
}
$this->data[$key][] = ['data' => $data, 'scheme' => $data_scheme];
}
public function changeData( $key, $new_data )
{
if( dataDoesNotRespectScheme( $this->data[$key]['scheme'], $new_data ) ) {
//Fail.
} else {
//Add the new data which is 100% identical in scheme to the old one.
}
//If we failed our checks
return False;
}
As such, the developer only has to know about the data structure, but he's 100% guaranteed to get it, in essence, creating a data interface which means that no matter what, code relying on retrieving this saved cannot fail.
Is this what the global state must overcome to be accepted?
If not, what would be a better solution to this or is the original intent of "I want to access data everywhere" a bad way of doing things?