So I have something like this:
class SomeClass{
//do some stuff
}
$variable = new SomeClass();
Now that in a php file called SomeClass.php for example, I want to in some other class called OtherClass.php do something like:
class OtherClass{
function doSomething(){
$variable->call_some_method();
}
}
How would I achieve this? I have thought of global variables, but then I see frameworks like Zend doing stuff like: $this->view->what_i_want_to_pass_to_the_view = 'hello apple sauce';
So what's a good way to do, essentially what I want to do.
Note: Some people are assuming I want to do global variables, this is not true. I am trying to replicate how Zend does something like $this->view in a class to send something to the view and then in the view, calls $this->view to get what was sent. I assumed this was done through globals...
This concept is called "Dependency injection" and is considered to be a best practice for doing even that.
class SomeClass{
//do some stuff
}
$some = new SomeClass();
class OtherClass{
function doSomething(SomeClass $some){
$some->call_some_method();
}
}
$otherclass = new OtherClass();
$otherclass->doSomething($some);
Alternatively, you can just inject the dependency on constructing time:
class OtherClass{
private $some = null;
function __construct(SomeClass $some){
$this->some = $some;
}
function doSomething(){
$this->some->call_some_method();
}
}
Depends on what you want to achieve and how often you need the dependency.
First, I’d like to congratulate you on finding a way to introduce global variables to Zend Framework as it breaks everything Zend Framework is about (OOP, MVC architecture etc).
Secondly, it’s bad practice. It’s possible, but bad too. If you find you’re struggling to do something with the language, then chances are there’s an easier way accomplish what you’re trying to do.
Although this isn’t an answer, I’d implore you to divulge more into your problem and why you’re wanting to use a class instance, globally-defined, in another class rather than an abstract example. Chances are, we can then help you become a better programmer by offering an alternative approach rather than instilling bad practices for you to go about building your websites and web applications.
I believe what you need is 'extends' i'll give you an example.
class Hello {
public function world() {
echo 'Hello World!';
}
}
class someClass extends Hello {
public function doSomething() {
$this->world();
}
}
$obj = new someClass();
$obj->doSomething();
There are a few ways of doing it:
1) Extend SomeClass
class OtherClass extends SomeClass
{
function doSomething(){
$this->call_some_someclass_method();
}
}
2) Pass the SomeClass instance into the OtherClass (not good coding practice)
$a = new SomeClass();
$b = new OtherClass();
$b->someInstance($a);
class OtherClass extends SomeClass
{
function someInstance($someClass){
$this->someClass = $someClass;
}
function doSomething(){
$this->someClass->call_some_method();
}
}
3) Create an instance inside OtherClass
class OtherClass extends SomeClass
{
function someInstance(){
$this->someClass = new SomeClass;
}
function doSomething(){
$this->someInstance();
$this->someClass->call_some_method();
}
}
Related
I want to be able to use the trait if it's available.
Obviously i cannont define that inside the class itself (syntax Error)
//fails
include_once('myTrait.php');
class foo
{
var $bar;
if (trait_exists('myTrait')) {
use myTrait;
}
}
//also fails
foo use myTrait;
//also fails
$f = new foo();
$f use myTrait;
//also fails
$f = new foo() use myTrait;
Ideal case scenario would be something like this:
class foo
{
var $bar;
}
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
//make class foo use myTrait;
}
$f=new foo();
Having hard time finding documentation and traits doesn't seems very popular but in my particular case they are very useful. I also try to keep resource as low a possible by only including files if needed.
Hints, documentation and explanation welcome as usual.
The closest my search brought me was in this article http://brendan-bates.com/traits-the-right-way/
Let's say a few of these controllers (but not all of them) require a
database connection. To keep performance up, we shouldn't give every
controller the database connection. What we could do is write an
abstract class which extends BaseController which provides a database
connection. But, in the future, what if an object that is not a
controller requires a database connection? Instead of duplicating this
logic, we can use horizontal reuse.
A simple trait can be created:
trait DatabaseAware
{
protected $db;
public function setDatabase($db)
{
$this->db = $db;
}
protected function query($query)
{
$this->db->query($query);
}
}
This trait now provides classes with common database functionality.
Any class which requires a database connection, be it a controller or
a manager (or anything), can use this trait:
class IndexController extends BaseController
{
use DatabaseAware;
public function indexAction()
{
$this->query("SELECT * FROM `someTable`");
}
}
Where as I implement traits depending on the needs of my different objects. Database connection, debugging reporting, etc.
Easy!
Trait
A trait that might be available or not, will be either used or not, but will eventually help to implement an interface:
<?php
trait BarTrait
{
public function bar()
{
return 'Hey, I am your friend!';
}
}
Interface
An interface we are looking to implement:
<?php
interface BarInterface
{
/**
* #return string
*/
public function bar();
}
Class using trait
A class FooUsingBarTrait which uses a trait BarTrait to implement the aforementioned interface:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
Class not using trait
A class FooNotUsingBarTrait which does not use a trait BarTrait, but instead implements the aforementioned interface itself:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
Conditionally create class definition
Finally, conditionally define a class Foo, depending on whether a trait BarTrait exists or not:
<?php
if (trait_exists(BarTrait::class) {
class Foo extends FooUsingBarTrait
{
}
} else {
class Foo extends FooNotUsingBarTrait
{
}
}
Create your instance
$foo = new Foo();
$foo->bar();
var_dump(
get_class($foo),
class_parents(Foo::class)
);
Note This probably makes most sense if both classes FooUsingBarTrait and FooNotUsingBarTrait implement a common interface - after all, you probably want to provide some functionality which will be shared between the two implementations: one using a trait, the other by other means (methods provided by that class).
For reference, see:
http://php.net/manual/en/function.class-parents.php
http://php.net/manual/en/function.trait-exists.php
For examples, see:
https://3v4l.org/fCLkt
https://3v4l.org/f77cn
no matter how bad it is, you can do it by extending the class.
trait AutoPilot {
function navigate() {
echo 'navigating...';
}
}
if (trait_exists('AutoPilot')) {
class Machine {
use AutoPilot;
}
} else {
class Machine {
}
}
class Car extends Machine {
}
$car = new Car;
$car->navigate();
Your question is fun, and eval() likely meets your needs. This style using code generation is ugly, but I know it works because I verified it myself on my own machine. Here's how you can do it:
$src = '
class foo {
var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
$src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared
I don't use eval() often, but it's fun when it solves a problem that otherwise cannot be conventionally solved.
Here what i've ended up with :
eval("class myClass {"
. (trait_exists('myTrait') ? "use myTrait;" : "")
. str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);
Total lazyness:
Duplicate trait_exists line to add more traits
Comments out the class keyword and the <?php tag so you don't have to edit the class file
evaluates the one long line of smelly code.
This works just fine for me and 'as is' without any modification to any file except the one i paste this line in. It will probably won't be the case for you.
Consider the fact that:
don't use closing php tag
only one class by file
you need to add any other keywords (extends, implements,...)
and probably way more unexpected behaviour depending on your code
Thanks to lacalheinz for his instructive post but Steven aimed at the bulleyes with eval().
// in class
public function test () {
$this->__invoke();
}
$inst->test();
This test runs without any error.
My question: is there some reason why this should not be done? Are there any corner cases, hidden caveats, or does it behave like any regular function/method?
That should not work since there is no __invoke() method in your class:
class SomeClass {
public function test()
{
$this->__invoke();
}
}
$inst = new SomeClass();
$inst->test();
http://3v4l.org/JOBXn.
If you implement __invoke(), that should work:
class SomeClass {
public function __invoke()
{
var_dump('Invoke!');
}
}
$inst = new SomeClass();
$inst();
http://3v4l.org/mpG5d.
Magic methods can be called directly as you can see in the second test, but in my opinion it is not a good idea since they are some kind of hooks and their code could be executed unexpectedly.
I am currently building a little project with PHP whilst not using any static methods or global state.
My class' constructors currently look a little like this, I am just injecting the dependent objects upon creating an object instance.
class Something {
public function __construct(Name\Space\Object $object, Other\Name\Space $object2)
{
# Assign properties here
}
}
In one of my application's classes I need to create new instances of various objects through the calling of its methods. Something a little like below;
class Something {
public function getNewObject()
{
return new Name\Space\Object();
}
public function getNewObject2()
{
return new Name\Space\ObjectTwo();
}
}
Is this how it should be done whilst adhering to the standard rule of dependency injection?
I am unsure how else it could be done as if I inject the object into the constructor then I will only have one instance whereas I may need many within my application?
Thanks,
I believe that functions are first class objects in PHP, so this should work:
<?php
class MyClass {
function foo() {
return 'foo';
}
};
class MyOtherClass {
function __construct($klass) {
$this->klass = $klass;
}
function get_instance() {
return new $this->klass();
}
}
$factory = new MyOtherClass(MyClass);
$obj = $factory->get_instance();
?>
// <h1> value should equal foo
<h1><?php echo $obj->foo();?></h1>
Edit: Tested and works.
I think my question is kind of noobish but i can't figure out how this stuff is working with PHP. It is a autoloaded class and I want to use my logging class for it.
I know I could have $log also as instance variable but I want it like that.
namespace Bal\Blub;
$log = new Logger('activities');
$log->pushHandler(new StreamHandler(__DIR__.'/../../log/activties.log', Logger::DEBUG));
$log->debug("is working here");
class Foo {
public function bar() {
global $log;
$log->debug("this is my message");
}
}
I don't understand why $log has no value in that case...
Edit: Of course I meant global and not public.
Ok so thanks for your code-style advises. I am quite aware that globals are bad practice. Though it was not my question. The answer for it is to use the global also in the namespace scope, which makes sense, but is a little strange if you are used to the PHP scripting approach.
namespace Bal\Blub;
global $log;
$log = new Logger('activities');
$log->pushHandler(new StreamHandler(__DIR__.'/../../log/activties.log', Logger::DEBUG));
$log->debug("is working here");
class Foo {
public function bar() {
global $log;
$log->debug("this is my message");
}
}
it is global $log. not public $log.
but be careful. globals are always evil. if you really need globals, use at least static variables.
<?php
class Globalholder{
public static $log;
}
Globalholder::$log = new Logger(...);
function foo(){
$log = Globalholder::$log;
$log->logsomething("Hello World");
}
global keyword, a static class property acting like a global variable, a singleton class...all can work, but since we're at it, why not trying to avoid bad practices and use DI?
Right now, your Foo class is tightly coupled with the Logger class, and that can make maintaince hard whenever, some day, you're going to change all the reference to the Logger class.
Why not something simpler like:
class Foo
protected $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function bar($string)
{
$this->logger->debug($string);
}
}
$log = new Logger('activities');
$foo = new Foo($log);
$foo->bar("test");
This way you're decoupling (I know this code can be made even better) the two classes, and you're also making the code easy testable by passing a mock Logger object.
class foo(){
function bar()
{
$classInstance = $this->createClassInstance($params);
$result = $classInstance->getSomething();
}
function createClassInstance($params)
{
require 'path/to/class.php';
$myClass = new Class;
$myClass->acceptParams($params['1']);
$myClass->acceptMoreParams($params['2']);
.... lots more params
return $myClass;
}
}
Can I initiate a new class by calling a method that returns a class object? The class in question has lots of parameters and I need to call it multiple times within bar() so I thought it would be neater to do it that way, but I can't get it working and want to check if it's possible + good practice?
That's called factory class (Factory OO Design Pattern).
How it should be done in PHP: http://www.php.net/manual/en/language.oop5.patterns.php
What I think you're describing is the Factory pattern, but you're using parameters to set the class variables just like you would in a constructor, so why not just use that?
Edit:
Ah, if you're using the same parameters for the most part then you definitely want the Factory pattern. Just use a static function to return an instance of the class, and put it inside the type of class you're returning:
class MyClass
{
public static function factory($params)
{
$myClass = new MyClass;
$myClass->acceptParams($params['1']);
$myClass->acceptMoreParams($params['2']);
//.... lots more params
return $myClass;
}
}
class foo(){
function bar()
{
$classInstance = MyClass::factory(param1, param2);
}
}