I am working on a backend project. I need to return a static object withing another static object:
Class this_is_a_very_long_class_name
{
public static function call()
{
return self;
}
public static function script_link($link)
{
//doing stuff here...
}
}
Class Main
{
public static function view()
{
// trying to return View object
return this_is_a_very_long_class_name::call();
}
}
and I am trying to use it like this:
Main::view()::script_link('Some script');
So how can I accomplish that?
P.S.: I am not looking for another solution. I am looking for a answer what I asked.
You don't need that.
Use
View::script_link();
Also this is wrong and misleading view()->script_link because script_link is static
Addendum
If you your problem is your class name length I suggest you to create simple wrapper for this.
function createLink($string){
return VERY_LONG_CLASS_NAME_HELLO_PHP_NAMESPACE::script_link($string);
}
this way you just need to createLink();
in php 5.3: return new View(); (instead of return View::self;).
Manual: http://php.net/manual/en/language.oop5.basic.php#example-159
in php 5.2 use ReflectionClass
I think your syntax on the call is wrong. Since it is static, what you are trying to do would look something like this:
Main::view()::script_link('Some script');
Except that would give you a syntax error. Also, since it is static, you don't need to return anything. You should make it two separate calls:
Main::view();
View::script_link("Some script");
It makes no sense to say "I need to return a static object". If the class is defined, then the static object is present and can be accessed.
You just need a variable to hold the class, as a direct call is invalid syntax
Sample:
Class Main
{
public static function view($type)
{
// return some class
switch ($type) {
case "View 2":
return View2;
break;
default:
return View;
}
}
}
$v = Main::view("normal view");
$v::script_link('test');
Are you looking for functionality as late static binding? Which is supported from PHP 5.3. See here: http://php.net/manual/en/language.oop5.late-static-bindings.php
Related
I want to call a static method from a variabe class in PHP. As pointed out several times on SO and because it is general practice, the following works as expected:
class Foo {
public function compile($strClass) {
$strClass::find(); // this works
}
}
Nonetheless I have to call different find methods from $strClass from different methods of a class Foo. That is, why I want to store $strClass in $this->strClass. Unfortunately, this doesn't work:
class Foo {
protected $strClass;
public function __construct($strClass)
{
$this->strClass = $strClass;
}
public function compile($strClass) {
$this->strClass::find(); // this does not work
}
}
Any idea or hint on how to solve that issue?
Update:
As pointed out in the comments, it might be a solution to use call_user_func like this:
call_user_func(array($this->strClass, 'find'), $strParam);
Anyhow, this makes code completion in PHPstorm impossible. Any hints on that? Maybe using code annotation?
You can change your compile method to this:
public function compile($strClass) {
call_user_func(array($this->strClass, 'find'));
}
This class design is flawed. I would try to get rid of the static methods completely, but here is a solution that exploits the fact that you can call static methods on objects:
class Foo {
protected $strClass;
public function __construct($strClass)
{
$this->strClass = new $strClass;
}
public function compile($strClass) {
$this->strClass::find();
}
}
UPDATE: nevermind, this is a syntax error in all current PHP versions, you actually have to do it like this:
$strClass = $this->strClass;
$strClass::find();
And this works with your original code as well, where $this->strClass is a string.
I have seen in Laravel calling multiple method in the single line, example:
DB::get('test')->toJson();
I have a cool class and view method in that class.
$this->call->view('welcome')->anotherMethod();
I would like to call another method also? Where should I make that method?
DB::get() seems to be a method returning an object, where you can call other functions (I think a result object of a database query). If you want to call multiple functions on one object in one line, you have to return $this in your functions, e.g.:
class View {
public static function factory {
// The question is: How useful is this factory function. In fact: useless in
// the current state, but it can be extended in any way
return new self;
}
public function one() {
// do something
return $this;
}
public function two() {
// do something
return $this;
}
}
Then you can do:
$class = new View();
$class->one()->two();
// it's also possible to use the `factory` function
// you should think about, how useful this approach is in your application
$class = View::factory()->one()->two();
That's how you can do it in php, if laravel has some helpers for that, i can't say :)
I've got an Object Oriented library I wanted to add a method to, and while I'm fairly certain I could just go into the source of that library and add it, I imagine this is what's generally known as A Bad Idea.
How would I go about adding my own method to a PHP object correctly?
UPDATE ** editing **
The library I'm trying to add a method to is simpleHTML, nothing fancy, just a method to improve readability. So I tried adding to my code:
class simpleHTMLDOM extends simple_html_dom {
public function remove_node() {
$this->outertext = "";
}
}
which got me: Fatal error: Call to undefined method simple_html_dom_node::remove_node(). So obviously, when you grab an element in simpleHTML it returns an object of type simple_html_dom_node.
If I add the method to simple_html_dom_node my subclass isn't what will be created by simplHTML ... so stuck as to where to go next.
A solution would be to create a new class, that extends the one from your library -- and, then, use your class, which have have all methods of the original one, plus yours.
Here's a (very quick and simple) example :
class YourClass extends TheLibraryClass {
public function yourNewMethod() {
// do what you want here
}
}
And, then, you use your class :
$obj = new YourClass();
$obj->yourNewMethod();
And you can call the methods of the TheLibraryClass class, as yours inherits the properties and methods of that one :
$obj->aMethodFromTheLibrary();
About that, you can take a look at the Object Inheritance section of the manual.
And, as you guessed, modifying a library is definitly a bad idea : you'll have to re-do that modification each time you update the library !
(One day or another, you'll forget -- or one of your colleagues will forget ^^ )
You could do it with inheritance, but you could also use a decorator pattern if you do not need access to any protected members from SimpleHtml. This is a somewhat more flexible approach. See the linked page for details.
class MySimpleHtmlExtension
{
protected $_dom;
public function __construct(simple_html_dom $simpleHtml)
{
$this->_dom = $simpleHtml;
}
public function removeNode(simple_html_dom_node $node)
{
$node->outertext = '';
return $this;
}
public function __call($method, $args)
{
if(method_exists($this->_dom, $method)) {
return call_user_func_array(array($this->_dom , $method), $args));
}
throw new BadMethodCallException("$method does not exist");
}
}
You'd use the above like this
$ext = new MySimpleHtmlExtension( new simple_html_dom );
$ext->load('<html><body>Hello <span>World</span>!</body></html>');
$ext->removeNode( $ext->find('span', 0) );
I don't why adding the method would be bad, however if you want to so without editing the library, your best bet would be to extend the class like so:
class NewClass extends OldClass {
function newMethod() {
//do stuff
}
}
class myExtenstionClass extends SomeClassInLibrary
{
public function myMethod()
{
// your function definition
}
}
As Pascal suggests... read the manual :-)
I tried these two ways:
(new NewsForm())->getWidgetSchema();
{new NewsForm()}->getWidgetSchema();
With no luck...
PHP does not allow you to do this. Try:
function giveback($class)
{
return $class;
}
giveback(new NewsForm())->getWidgetSchema();
It is a rather weird quirk with the language.
You can't an instanciation and a method call in one instruction... But a way to "cheat" is to create a function that returns an instance of the class you're working with -- and, then, call a method on that function which returns an object :
function my_function() {
return new MyClass();
}
my_function()->myMethod();
And, in this kind of situation, there is a useful trick : names of classes and names of functions don't belong to the same namespace -- which means you can have a class and a function that have the same name : they won't conflict !
So, you can create a function which has the same name as your class, instanciates it, and returns that instance :
class MyClass {
public function myMethod() {
echo 'glop';
}
}
function MyClass() {
return new MyClass();
}
MyClass()->myMethod();
(Yeah, the name of the function is not that pretty, in this example -- but you see the point ;-) )
If it is a static method you can just do this:
NewsForm::getWidgetSchema();
A better option in my opinion would be to use a factory method:
class factory_demo {
public static function factory()
{
return new self;
}
public function getWidgetSchema()
{ }
}
then
factory_demo::factory()->getWidgetSchema()
Of course, you get all the benefits of the factory pattern as well. Unfortunately this only works if you have access to the code, and are willing to change it.
I would like to know whether there's a way to chain methods on a newly created object in PHP?
Something like:
class Foo {
public function xyz() { ... return $this; }
}
$my_foo = new Foo()->xyz();
Anyone know of a way to achieve this?
In PHP 5.4+, the parser's been modified so you can do something like this
(new Foo())->xyz();
Wrap the instantiation in parenthesis, and chain away.
Prior to PHP 5.4, when you're using the
new Classname();
syntax, you can't chain a method call off the instantiation. It's a limitation of PHP 5.3's syntax. Once an object is instantiated, you can chain away.
One method I've seen used to get around this is a static instantiation method of some kind.
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
static public function instantiate()
{
return new self();
}
}
$a = Foo::instantiate()->xyz();
By wrapping the call to new in a static method, you can instantiate a class with method call, and you're then free to chain off that.
Define a global function like this:
function with($object){ return $object; }
You will then be able to call:
with(new Foo)->xyz();
In PHP 5.4 you can chain off a newly instantiated object:
http://docs.php.net/manual/en/migration54.new-features.php
For older versions of PHP, you can use Alan Storm's solution.
This answer is outdated - therefore want to correct it.
In PHP 5.4.x you can chain a method to a new-call. Let's take this class as example:
<?php class a {
public function __construct() { echo "Constructed\n"; }
public function foo() { echo "Foobar'd!\n"; }
}
Now, we can use this: $b = (new a())->foo();
And the output is:
Constructed
Foobar'd!
Further information may be found on the manual: http://www.php.net/manual/en/migration54.new-features.php
Well, this may be an old question but as with a lot of things in programming - eventually the answer changes.
Regarding PHP 5.3, no, you can't chain directly from the constructor. To expand on the accepted answer however, in order to properly accommodate for inheritance, you can do:
abstract class Foo
{
public static function create()
{
return new static;
}
}
class Bar extends Foo
{
public function chain1()
{
return $this;
}
public function chain2()
{
return $this;
}
}
$bar = Bar::create()->chain1()->chain2();
That will work just fine and will return you a new Bar() instance.
In PHP 5.4, however, you can simply do:
$bar = (new Bar)->chain1()->chain2();
Hopefully this helps someone stumbling across the question like I have!
It would be really helpful if they 'fix this' in a future release. I really appreciate the ability to chain (especially when populating collections):
I added a method to the base class of my framework called create() that can be chained off of. Should work with all descendant classes automatically.
class baseClass
{
...
public final static function create()
{
$class = new \ReflectionClass(get_called_class());
return $class->newInstance(func_get_args());
}
...
public function __call($method, $args)
{
$matches = array();
if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
{
// Magic chaining method
if (property_exists($this, $matches['prop']) && count($args) > 0)
{
$this->$matches['prop'] = $args[0];
return $this;
}
}
}
...
}
Class::create()->SetName('Kris')->SetAge(36);
Just for the sake of completeness (and for the fun of it...), since nobody seems to have mentioned the solution with the shortest (and least sophisticated) code.
For frequently used short-lived objects, especially when writing test cases, where you typically do lots of object creation, you may want to optimize for typing convenience (rather than purity), and sorta' combine Alan Storm's Foo::instantiate() factory method and Kenaniah's with() global function technique.
Simply make the factory method a global function with the same name as the class!. ;-o (Either add it as a convenience wrapper around the proper static Foo::instantiate() or just move it out there while nobody is looking.)
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
}
function Foo()
{
return new Foo();
}
$a = Foo()->xyz();
NOTE:
I WOULDN'T DO THIS on production code. While kinda' sexy, this is an abuse on basic coding principles (like "principle of least surprise" (although this is actually rather intuitive syntax), or "don't repeat yourself", esp. if wrapping a real factory method with some parameters, which itself, BTW, is already an abuse of DRY...), plus PHP may change in he future to break code like this in funny ways.