I have php file which contains class "FooClass" uses in a few projects. I recently add method for logging with log4net like this:
private static function log($message,$level=0)
{
if(!isset(self::$logger))
{
if(!class_exists("Logger")) return;
self::$logger = Logger::getLogger("DBw");
if(!isset(self::$logger)) return;
}
//logging
}
Some files that use FooClass can define the configuration by ising Logger::configure("config.xml").
But others don't define it, and in that case the FooClass start to use LoggerConfiguratorDefault, which trace logs as "echo". This is not acceptable.
I want to see if the configuration is not defined by other files, the FooClass did not log with LoggerConfiguratorDefault.
How can I do disable LoggerConfiguratorDefault or detect using of that and make return from function?
I was in the same position, slightly different case: My configuration object does log if I access a value, but it cannot log if I access the config value for the configuration file of the logger.
The class Loggerof log4php has a private static property $initialized, which is accessed through a private static method isInitialized(). I solved my problem by using Reflection to access the value of the static property, and if the result was false I returned a self-created NullLogger extends Logger that does nothing if any logging methods are called.
Your class might be able to do the same, but the better solution will be to ensure log4php always is initialized.
I'd suggest that you create a ticket in the projects Jira to have this issue resolved more easily. There really is no need to have the Logger::isInitialized() method private.
Related
I need static class (object) to store a global variable value. I'm new in PHP but i have experience in other language that have OOP concept like in Java. In Java i can make static variable and can call anywhere i want. But how to do same in PHP?
I use CodeIgniter framework , before i try this i try using session to store but i want to use another way like above. can anyone help me?
Can i do like this ?
static class myClass{
public static myVar = "";
}
Because you mentioned framework Codeigniter and use of session I assume that you need to use this in multiple controller and views.
So I there is also another way which works bit different than property of class but more similar than session (except changed value won't affect on another page).
So Use Constant.
Define it in
application > config > constant.php
page. There are many constant defined in that page, using exact same syntax you can define your values and you can use it very easily to any where.
just like if you define SITE_NAME constant in constant.php as
defined('SITE_NAME') OR define('SITE_NAME', "My Example Site");
After that you can use it anywhere in any controller, view or model of your Codeigniter, What you need to do is just echo it
<?php echo SITE_NAME; //only SITE_NAME not $SITE_NAME ?>
I hope it is what you want, if not sorry for my misunderstanding.
You can have a static-like class in PHP. But you don't have an app-cycle in PHP. This means you won't get a real static (or singleton) in your whole application.
If you shouldn't be able to instantiate a class then it should be abstract and define its methods as static. However, somebody could just subclass the class and make it non-abstract. If you don't want that to be a possibility either then the class should be abstract final.
If you do this, you can call methods directly on the class in question with ClassName::methodName() syntax. Do bear in mind that classes written like this can't make use of $this because it is only valid for an object instance. If you need the class to maintain state then you will have to define a static variable and use it with self:: or static:: syntax.
abstract final class SomeClass
{
private static $var = "";
public static function setVar($newVal)
{
self::$var = (string) $newVal;
}
public static function getVar()
{
return self::$var;
}
}
A word of caution on doing this though, use of abstract classes/methods can very easily lead to tightly coupled code which is bad for a number of reasons.
For example, if you write a class that calls the methods of an abstract class directly by any means other than inheriting from the abstract class, then it will be impossible to unit test that class in isolation. It will always require your abstract class to be part of the test suite too, which means it's more difficult to determine whether a test failure has been caused by a fault in the class under test or in the abstract class it's depending on.
What's more, if the abstract class you're depending on serves as an accessor for a data source, then you also will not be able to mock the class during tests. Mocking is a very powerful way of verifying the correctness of a class without having to rely on the environment that the class is running in. for example, you can mock a database access class with a compatible object that always returns the same data from an array instead of hitting an actual database. This means that you can guarantee that when you run a test it will run with data in a state that you have full control over. If you access a database via an abstract class's methods then you can't replace that for testing and suddenly you may end up with a test suite that might succeed or fail depending on the state of the database at the time you run the test. Even worse, if your tests involve writing to the database then you could potentially corrupt your data source when running tests.
I have looked online for the meaning of parent::init(); . All I was able to find was that init() is to initialize some settings which want to be present every time the application runs.
Can anyone please explain the meaning of parent::init() in exact sense, like significance of both the words?
Thanks in advance.( I am sorry if its too simple! )
When we use parent::init(), we are just calling the parent method (in this case init()) inside a method of the current class.
About parent::
For example, let's say we have a class called MyClass. This class have a awesome method that runs alot of things:
class MyClass
{
public function runStuffs()
{
// trigger events, configure external stuff, adding default values to properties.
}
}
Now, after some time, we decided to create a new Class that extends from the first one. And we called MySecondClass:
class MySecondClass extends MyClass
{
}
It already have the method runStuffs(), but, for this second class, we need to do more things in this method, but maintaining what it have.
Sure we could rewrite the whole method and just copy and paste what we have in MyClass and add the new content. But this isn't elegant or even a good practice. what if later on We change the method in MyClass, you probably would like that MysecondClass have that changes too.
So, to solve that problem, we can call the parent method before write your new content:
class MySecondClass extends MyClass
{
public function runStuffs()
{
parent::runStuffs();
// do more things!
}
}
Now MySecondClass->runStuffs() will always do what its parent do and, after that, more stuff.
About the init() method.
init() is a method used in almost all classes from Yii2 framework (since most of then extends from yii\base\Object at some point) and works just like the __constructor() method (native from PHP). But there is some differences, you can read more here.
Actually the init() method is called inside the __constructor(), and the framework encorage us to use init() instead of __construct() whenever is possible.
Now if both are pretty much the same thing, why do they create this method? There is an answer for that here. (take a look at qiang's answer, from the dev team):
One of the reasons for init() is about life cycles of an object (or a component to be exact).
With an init() method, it is possible to configure an object after it is instantiated while before fully initialized. For example, an application component could be configured using app config. If you override its init() method, you will be sure that the configuration is applied and you can safely to check if everything is ready. Similar thing happens to a widget and other configurable components.
Even if init() is called within constructor rather than by another object, it has meaning. For example, in CApplication, there are preInit() and init(). They set up the life cycles of an application and may be overridden so that the customization only occurs at expected life cycles.
Conclusion
So, when you use a init() method and calls parent::init() you are just saying you want to add more things to that method without removing what it already was doing.
The parent::init(); Method is useful to execute a code before every controller and action,
With an init() method, it is possible to configure an object after it is instantiated while before fully initialized.
For example, an application component could be configured using app config.
If you override its init() method, you will be sure that the configuration is applied and you can safely to check if everything is ready.
Similar thing happens to a widget and other configurable components.
In Yii, init() method means that an object is already fully configured and some additional initialization work should be done in this method.
For More Information check this link :
https://stackoverflow.com/questions/27180059/execute-my-code-before-any-action-of-any-controller
Execute my code before any action of any controller
might be helpful to you.
I'm trying to create my own session handler. I've found this resource. The problem with that, is that he make changes to vendor directory which is something I don't want to.
The reason for that is, I'm working with others, it's a collaborative project using version control system (pushing the main application ignore the vendor folder ) and besides that I presume with each composer install all changes will be lost (although I'm not sure).
It crossed my mind to change the DatabaseSessionHandler, after all , all I wanted was to change the field names of the table that Laravel uses for storing the session (I'm working on a pre-existing database), but it would be the same as I mentioned above.
Is there any way I could create my own session handler and use it in my application?
A service provider or something even better?
Links will be appreciated.
Update
Something I want to clarify, I want to be able to use Laravels API.
Another resource I've found is Laravels doc how to write a session extension, but I think a lot of stuff is missing. It says I have to create a service provider cause sessions are started very early in the request-lifecycle. Any directions from there?
It says I have to create a service provider cause sessions are started very early in the request-lifecycle. Any directions from there?
What that actually means is that you have to register a Session Service Provider in the IoC-Container very early in the request-lifecycle.
Since the bindings in your app/config/app.php will be registered very early during the bootstrapping process of laravel, it is the perfect place to bind your custom SessionHandler-Extension.
Basically you need the following things to tackle your problem:
A Service Provider that binds a new instance of a SessionHandlerInterface (your concrete Custom Session Handler) to the IoC Container
And edit in your app/config/app.php that adds your new Service Provider
Your Custom Session Handler Class
Let's get started:
Bootstrapping the Service Provider:
The Docs tell us to add our Custom Service Provider below the Illuminate\Session\SessionServiceProvider so in your app/config/app.php add the following line below laravel SessionServiceProvider:
'MyProject\Extension\CustomSessionServiceProvider',
Now during laravels bootstrapping process out CustomSessionServiceProvider will be loaded right after laravels. In our custom provider we will do the actual binding.
Creating the Service Provider:
Now that you made sure the Service Provider is being loaded we will implement it.
Within the service provider we can overwrite the binding of laravels DatabaseSessionHandler which we will do.
<?php namespace MyProject\Extension;
use Illuminate\Support\ServiceProvider;
use Session;
class CustomSessionServiceProvider extends ServiceProvider {
public function register()
{
$connection = $this->app['config']['session.connection'];
$table = $this->app['config']['session.table'];
$this->app['session']->extend('database', function($app) use ($connection, $table){
return new \MyProject\Extension\CustomDatabaseSessionHandler(
$this->app['db']->connection($connection),
$table
);
});
}
}
First we grab the connection type that we use to store our session and then the table where the sessions will be stored.
Since you only want to change column names we don't need to implement a whole new Database Session Handler. Instead let's extend Laravels Illuminate\Session\DatabaseSessionHandler and overwrite the necessary methods.
Laravels DatabaseSessionHandler has two dependencies. An implementation of the ConnectionInterface and a table name. Both are injected into our CustomDatabaseSessionHandler which you can see above.
Then we just return our CustomDatabaseSessionHandler in the closure.
Creating the actual CustomDatabaseSessionHandler
Now that we're ready to fire off the new CustomDatabaseSessionHandler let's create it.
There is not much to do. Only four methods use the hardcoded columns. We will just extend the Illuminate\Session\DatabaseSessionHandler class and overwrite those four.
<?php namespace MyProject\Extension;
use Illuminate\Session\DatabaseSessionHandler;
class CustomDatabaseSessionHandler extends DatabaseSessionHandler {
public function read($sessionId)
{
// Reading the session
}
public function write($sessionId, $data)
{
// Writing the session
}
public function destroy($sessionId)
{
// Destryoing the Session
}
public function gc($lifetime)
{
// Cleaning up expired sessions
}
}
Since you want to only change column names you can even copy the method bodies from the parent class and just change what you want.
That's it. Happy coding and have fun with Laravel!
When implementing, make sure you are locking the session as this is often forgotten and leads to unreliable session modifications. For more information read:
http://www.leaseweblabs.com/2013/10/symfony2-memcache-session-locking/
You are able to use SessionHandlerInterface
class MySessionHandler implements SessionHandlerInterface {
// implememntation
}
$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();
References
http://www.php.net/manual/en/class.sessionhandlerinterface.php
I have a simple importer class that logs success and failure statuses to a log file.
I have made the log file name a constant in the class like so:
class MyClass
{
const STATUS_LOG = "my_log.log";
public function doImport()
{
// do import here and log result
}
}
Currently i know of no reason that different logs would be used, but would it be better to allow that flexibility and do the following instead:
class MyClass
{
private $statusLog;
public function __construct($statusLog)
{
$this->statusLog = $statusLog;
}
public function getStatus()
{
return $this->statusLog;
}
public function setStatusLog($statusLog)
{
$this->statusLog = $statusLog;
}
public function doImport()
{
// do import here and log result
}
}
Given i currently have no use for different log files, is there any benefit in the second approach?
I think that in terms of logging you should not allow to change log path. Not in runtime - since there's a question - what will happen with data integrity if log path will changed 'on hot'? Flexibility sounds good, but I think this is not a case when you should allow change your property in runtime.
If you're hesitating about log path then it should be adjustable via configuration file - i.e. read once at application's start. So you will not store path in your class, reading it from config instead (in __construct() for your class).
If you have a static logfile path that doesn't change you can stay at the first one.
If it should be able to change the log path (weather now or in planned future) I would use the second one. (The benefit is just to be able to set and get the logpath, a getter can also be used for the firse solution).
This is a no-brainer. The second approach is more flexible and more explicit. Also, the log file name is not a "real" constant in the sense that, say, pi or equator length are. When defined as constant, it's just a "magic value" you'll sooner or later forget that it's there.
I'd get rid of the setter method though and only allow setting the value in constructor.
Your class might violate the single responsibility principle: from the doImport method I conclude that the first responsibility of your class is importing and it should not concern itself with the details of logging (formatting, what file to use, what to log in development/production environment). Why not pass in a logger class (preferably a class that implements the PSR-3 interface) in the constructor? Monolog is a fantastic and flexible logging library.
If you keep the filename (or better the logger) flexible, you can write unit tests for your class without having to worry about overwriting important files. If you use a memory/dummy logger class, you don't even need a file system!
If you just write a small one-off script that will not be tested however, then using a constant is a good way for configuration IHMO.
I am new to OO concepts in PHP. I have a class called MY_ controller which is my base class. All classes extend this class. I am using MVC architecture. I am using caching in my system now. So i load the cache variable in the constructor of my base class. I use normal php variable like $cacheVariable in my function to store the value from cache. I was wondering if it would serve any help if i store it as a class parameter and use like $this->cacheVariable? In each function i get cache value like $this->cache->get('cacheVariable'); will it help if i get value from $this->cacheVariable
If you want to be able to use $cacheVariable anywhere else besides your constructor you'll want to use $this
public function __construct() {
//...
$this->cacheVariable = $this->cache->get('cacheVariable');
//...
}
Also remember, if you want your children classes to inherit this variable from your base class you will need to set it as either public or protected. If it's private children will not inherit it.
When you say "class variable" I assume you are referring to a property (property of an instance=. Note the difference:
if you have a class, say MyClassA, then in your scripts you will instantiate that class using the operator new (depending on your PHP version you can use a different constructor syntax it changed since PHP-5.3.0):
<?php
class MY_controller{
public $cacheVariable;
// constructor
function MY_controller($aValue){
// constructor code which loads cacheVariable, for example with parameter
$this->cacheVariable = $aValue;
}
public function someFunction(){
//... some code, then access the property
$cv = $this->cacheVariable;
}
}
$aController = new MY_controller(42);
?>
As you inherit from MY_controller, every instance of that class, will have access to cacheVariable through $this->cacheVariable.
The important thing I wanted to clarify is that it is an instance property, not a class one. For further reference on OOP in PHP, refer to the properties section in PHP's OOP manual and the inheritance section.
When you instantiate only one instances of your controller (derived from your main controller), its a conceivable solution.
In my opinion the better idea is getting variable directly from cache service everywhere you want in your class and don't keep it as a class property. The reason is simple: let's say value of some key from cache will be changed (or expires) in the other place than your class. If you have this value as class property you need to keeping eye on it every time you access this value but if you retrieving it from cache you just don't care (because the cache cares if value of some key doesn't changed or expired).