I know... stay away from globals.
The thing is I really, really, need to have a value that is accessible and, most important modifiable from different parts of the application. It's a counter for some actions that I need to watch for debug purposes. Googling for anything related to Symfony and globals, always got me to results that suggests using the Container parameters or Twig globals, but the thing is that according to Symfony documentation:
You can only set a parameter before the container is compiled: not at run-time.
The Twig globals are pretty much out of scope given that I need them in controller, not in view.
IMHO, both of these solutions are more like constants than variables.
So, the question is: Is there a best practice to obtain what I need using Symfony or should I just use the PHP globals?
Thank you!
Create a service (e.g: ApplicationGlobals) with a private property $counter and public setter and getter to read and write the value. A service class will be instantiated automatically and can be reached from everywhere where you can use the container (get it in the controller or pass it as an argument to other services).
Latter you will be able to add multiple variables, when needed, with their proper getters and setters and use them in your project.
I think you could even write a destructor that stores the new value when Symfony terminates. http://symfony.com/doc/current/service_container.html#creating-configuring-services-in-the-container
Why not use the parameters section in services.yaml ?
It seems that you can also define/modify variables programmatically :
$container->parameters()->set('app.admin_email', 'something#example.com');
https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
https://symfony.com/doc/current/configuration.html#configuration-parameters
Related
I see advise from a lot of people teach not to use global variable/singleton/static class and move to use of a iOC container, for example, in PHP larvel framework, it is
App::bind('foo', function($app)
{
return new FooBar;
});
$value = App::make('foo');
instead of
$value = new FooBar;
But to me, the App::bind itself is a static method and cannot be replaced easily.
So, can I say, the iOC (at least in PHP), is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right?
App::bind is not a static method, this is it's signature:
public function bind($abstract, $concrete = null, $shared = false)
(found in /vendor/laravel/framework/src/Illuminate/Container/Container.php)
Laravel uses Facades, which, while they look like they are calling a method statically, actually instantiate an object under the hood and then call an instance method on that object. While Laravel does use some static methods in it's models, the App object itself is actually a facade. You can see a list of the built in facades if you look in /vendor/laravel/framework/src/Illuminate/Support/Facades/.
So, can I say, the iOC (at least in PHP), is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right?
You are seeing this correctly, but you can actually reduce the number of hard coded variable to 0.
The problem here is not App::bind() because it's configuration. Configuration has to be coupled to some kind of system because that's where you set all the details. That's OK here.
But having App::make() all over your codebase is the problem. You want to write reusable code. You don't want your model to be coupled to Laravel for example. The fact of calling the container is called the service locator pattern (because you locate services with the IoC).
This is an anti-pattern, because, as I've said, you are coupling your code to the container.
On the other hand, there is the dependency injection pattern which is better. Dependencies are injected in your classes, but you don't care how. This is just pure PHP, completely decoupled from any container.
I invite you to read stuff on the subject, Laravel can actually be used with full dependency injection (no static calls to Facades). Here is an article on the subject: Using Dependency Injection and IoC in Laravel 4 controllers
Howard, I think the context you might be missing is why people say
global variable/singleton/static class
are "bad". The reasons you don't want global variables in your application is, relying on global state is going to lead to pain. When you're modifying values that other parts of the program also have access to, it's likely two parts of a program are going to access that same variable and unexpected "bad" things will happen. Singletons and static classes are often lumped in with global state, because they're globally available things.
So yes, your statment
is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right
is accurate, but more than that a service container (if services are being created correctly) gives you global access to a thing-to-do-a-job, but is makes it hard/impossible to use that global thing-that-does-a-job to store global application state.
I can't find how to make something like ::getInstance() like in other php frameworks to get Application (singleton) instance in symfony2
I found only sfContext::getInstance() buy it doesn't work and looks like its method from symfony1
add more info.
I have some class - abstract class Post { }. I want to get some application config, environment variables inside this class. i don't want to put all this stuff to constructor method, instead i want to call application instance and get all i want
If you take a look at web/app.php you will see that your application instance is just a global variable called kernel
$kernel = $GLOBALS['kernel'];
die(get_class($kernel));
However, the reason #san40 told you to read the documents is that you probably never actually need it for anything. SF2 is very different than SF1. So if you explained why your wanted the instance then someone might be able to suggest alternative approaches.
===================================
Looking at web/console shows that same principle for console commands except the instance is called application.
die(get_class($GLOBALS['application']))
However, using the application instance to pull environment variables and such is not recommended. If nothing else, it makes your objects completely dependent in the instance. Dependency injection is what you want. Read through the stuff in the s2 documentation.
I've got this Config-class that I use in my PHP5 application to load & parse my static config. This far I've managed to keep the class from being a singleton/registry and instead passed the instance of the Config class around to wherever it's needed with the help of Dependency injection.
But now as I need to set/make changes in my Config during runtime at one place, my changes aren't reflected globally and being far from a specialist with the use of the static modifier in PHP, I need to ask:
What is the best way to ensure that changes to the properties in my Config-class are reflected throughout my application without making the class into a singleton? Can I just make the variable holding the config data static?
This far I've managed to keep the class from being a singleton/registry and instead passed the instance of the Config class around to wherever it's needed with the help of Dependency injection.
If you pass the same instance of your Config class to every part of your application and you change a setting it should be reflected everywhere else.
In case you are creating multiple objects of the class (and parse that config file every time?!) you might want to stop doing that. It's possibly wasteful and I'd say it is confusing.
So if you create only one and pass that around everything should be fine.
Under the assumption that you create multiple instances of the object that only should exist once:
If you are able to "fix" your architecture to allow you to do that: Do so.
If you can't to that... well.. creating a static property to hold your values in a class that you can have multiple instances off is, at least in my book, a major wtf factor. If you can't fix (meaning it's to much off a hassle to do so) just "break" it in an expected way so other people don't trip over it.
I'd rather have a singleton than something that creates all the issues with singletons and also lies about being a wrapper for a global variable.
Blindly avoiding design patterns because you hear on Internet forums that they're bad is about as much an anti-pattern as singletons are in general. If a tool is right for a job, then it's right.
Look at your question, you're trying to emulate singletons through a complex multi-update system for God's sakes... And just so you know, making a class static is essentially turning it into a singleton, albeit an insecure one that can be overwritten at any time.
TL;DR: Think for yourself and use the right tools; make your config class a singleton.
In a theoretical database access class, I found that there are quite a few helper functions that I use in the class, which have nothing to do the class's instance (and others, that could be manipulated to be unrelated to the class's instance using dependency injection).
For example, I have a function that gets a string between two other strings in a variable. I've been thinking of moving that to a String_Helper class, or something of the sort. This function has already been made static.
Also, I have a function that queries a database, query($sql). The connection details are provided by the instance, but I've been considering making it static, and using query($sql, $connection). Developers would then be able to call it statically and not need to instantiate the database class at all.
For me, the questions are:
Is it worth it to do something like this? Functions like the query function make me wonder if this is not just me trying to make everything as static as possible, without any real need to. Under what circumstances would you consider this useful?
I know static functions are harder to test, but if I make sure that their code is completely dependency free (or uses dependency injection where necessary), then they're just as easy to test as everything else, surely?
It isn't a concern at the moment, but if, in the future, I decided to extend the classes with the static functions, it would be impossible for me to make the current code use my extended functions. I've thought of Singletons, but the same problem arises: the code would be calling Singleton_Class::getInstance(), and not My_Extended_Singleton_Class::getInstance(). Dependency Injection seems to be the only way to solve this issue, but it might lead to a clunkier API, as every dependency has to be given to an object on __construct().
I have a container class, which holds certain pieces of information statically so that they can be accessed anywhere in the script (global scope). If I can't use static functions or singletons, a class that contained instances of different variables would be great. One could use for example Container::$objects['MyClass'] = $MyClass_object;, and then the rest of the code could just access Container::$objects['MyClass']. If I extended the MyClass class, I could use Container::$objects['MyClass'] = $MyExtendedClass_object;, and the code that used Container::$objects['MyClass'] would use MyExtendedClass, rather than MyClass. This is by far the best way to do it, in my opinion, but I'd like to know what you think about it.
Ok, let me answer these one by one...
1. Is it worth doing something like this
Yes and no. Splitting out the helper functions into their own classes is a good idea. It keeps the "scope" of each of the classes rigidly defined, and you don't get creap. However, don't make a method static just because you can. The query method is there to make your life easier by managing the connection, so why would you want to lose that benefit?
2. They are harder to test
They are not harder to test. Static methods that depend on state are harder to test (that access static member variables or global variables). But static methods in general are just as easy to test as instance methods (in fact, they can be easier since you don't need to worry about instantiation).
3. Extending the classes
This is a valid concern. If you put String_Helper::foo() in the class itself, you'll run into issues. But an option would be to set the name of the string helper as a class variable. So you could then do {$this->stringHelper}::foo() (note, PHP 5.3 only). That way to override the class, all you need to do is change the string helper class in that instance. The Lithium framework does this a lot...
4. Global Registry
I would stay away from this. You're basically just making every class a singleton without enforcing it. Testing will be a nightmare since you're now dependent on global scope. Instead, I'd create a registry object and pass it to classes via the constructor (Dependency Injection). You still accomplish the same thing since you have a store for the objects/classes, but you're no longer dependent on a global scope. This makes testing much easier.
In general
When you're looking at doing things like this, I like to stop when I hit questions like this. Stop and sit down and think *What actual problem am I trying to solve?". Enumerate the problem explicitly. Then pull our your supposed solutions and see if they actually solve them. If they do, then think about the future and if those solutions are really maintainable in the long run (Both from a bug fix standpoint, and with respect to feature additions). Only if you're happy with both of those answers should you even consider doing it. Oh, and also remember to keep it simple. Programming is not about making the most complex, most clever or most amazing solution. It's about making the simplest solution that solves the problem...
I hope that helps...
Good Luck!
On application start I'm creating Config object (Singleton). How could I make Config object be available inside Model and Controller? Should I pass Config object to constructor as method parametr or I should better use $this->config = Config::getInstance()? Any other methods?
Thank you
Singleton is essentially just fancy syntax for a global variable, and is as bad as globals are (and they are bad). Passing a parameter is the cleanest option as it creates no hard coupling between classes and allows for maximum flexibility. Another reasonable (but rather advanced) option is to use a dependency injection container, see for example this post.
If Config is a Singleton, you can use pretty much any solution you'd like :
Passing it as a parameter is not needed, as it's global
But passing is as a parameter can allow for dependancy injection -- which might help if you want some automated tests
Storing it as a class property can be useful -- but it's not required either.
Generally, for that kind of object, I just use Config::getInstance() each time I need it, and don't store it in a class property.
But I guess this is a matter of personnal preferences...
I usually make it a instance singleton by means of Config::getInstance(), and add accesors in Environment#config (or Bootstrap#config , tutorials go with Bootstrap) and My_Top_Controller#config (this My_Top_Controller extends Zend_Controller and is the ancestor of all other controllers) and also add it to Zend_Registry via config key.