I have come across this line in the eloquent ORM library:
return with(new static)->newQuery();
I've never seen "with" used before, and cannot find it in the PHP documentation. I'm guessing "with" is a stop-word in most searches, so I am not even getting close.
Never having encountered "with" in many years of programming PHP, I feel like I'm missing out. What does it do? I did come across one passing comment regarding the ORM, that mentioned "with" is no longer needed in PHP-5.4, but that was as much as was said. If that is accurate, it would be good to know what the PHP-5.4 equivalent is.
Update: Details supporting the answer:-
I found this helper function in Laravel's Immuminate/Support/helpers.php helper script:
if ( ! function_exists('with'))
{
/**
* Return the given object. Useful for chaining.
*
* #param mixed $object
* #return mixed
*/
function with($object)
{
return $object;
}
}
as mentioned in a few of the answers. That global-scope function allows an object to be created and methods run in t, in one statement. It is (somehow) registered in the composer autoload_files.php script when Laravel is installed, so it gets loaded on every page, even though it contains no classes.
Thanks all. It pays not to assume that everything must be a namespaced class in modern frameworks.
It's a function that will look something like this:
function with($obj) {
return $obj;
}
It's shorter version and more readable version for new ExampleObj()->newQuery().
with function is not build in PHP. It's workaround for older versions than PHP 5.4. As #Rocket Hazmat pointed in PHP 5.4+ you can do just new ExampleObj()->newQuery() so with function here allow you to keep readable backward compatibility.
The with function is a helper provided by Laravel as documented here. The best documentation is the code and as you can see, it simply returns the object. In 5.4 / 5.4 you are better off just surrounding the expression in parens to avoid the overhead of an unnecessary function call.
I think #Izkata hit the nail on the head in the comments.
[I'm guessing] this is a workaround for something along the lines of new Foo()->newQuery() not working in some version of PHP
In PHP 5.4 the following was added:
Class member access on instantiation has been added, e.g. (new Foo)->bar().
(Source: http://www.php.net/manual/en/migration54.new-features.php)
So, I'd assume with looks something like this:
function with($x){
return $x;
}
In PHP 5.4+, you can do (new static)->newQuery(), but with an older version, you can't. with is probably there so you can do with(new static)->newQuery(), which will work in any PHP version.
Related
Since PHP7 it seems to be possible to directly call anonymous functions like this:
(function () { echo 'Hello!'; })();
I found this by accident in some open source code base. I tried to find any hint on this in the PHP documentation (including changelogs and RFCs). There seems to be none, it seems fully undocumented.
Is it safe to call functions this way or should I use call_user_func(); like in the old days? Is this documented somewhere?
I know of these questions and answers:
IIFE (Immediately Invoked Function Expression) in PHP?
https://stackoverflow.com/a/35044603/1708223
They just say it's supposed to work and how it works. I know this. My question is not about the "how"! It's about whether this is actually an official PHP feature or if it'S merely working "by accident" (because it seems undocumented).
The reason you won't find this documented as a feature in the main manual is because it isn't one, it's just a consequence of other features:
function () { echo 'Hello!'; } creates a Closure object
putting () after a Closure object executes that closure
That's not quite the same as accidental, but I can see why you might think that, because it didn't work in PHP 5.
The reason it changed is that PHP's parser was overhauled in PHP 7.0 to use more consistent rules when parsing variables, as well as introducing an extra stage called an Abstract Syntax Tree. This changed the meaning of some code, but allowed for other cases that logically should have been possible, but were previously hard to implement.
Allowing code that was previously a syntax error is not generally considered a compatibility break, so not every piece of syntax enabled by this change made it into migration guides.
However, removing this functionality - even if not documented - would be a compatibility break, so at the very least you will get some notice that it's going to change, and it would be in a "major version" (9.0, 10.0, etc). Since it's a useful piece of syntax, there's no reason to suppose it will ever stop working, unless there's some even more useful feature that conflicts with it for some reason.
Just to put some thoughts together: (function () { echo 'Hello!'; }) defines a class instance of type Closure. Putting the closure into a variable helps to understand that:
$x = (function () { echo 'Hello!'; });
echo gettype($x);
This prints object, since PHP 5.3. The result of $x(); hasn't changed since PHP 5.3 either. But what has changed is the unified handling of variables - this enables that you don't have to define a variable explicitly, but call the closure directly as if you had put it in a variable first
In Laravel, which is quite clever, they have a "helper" function "with":
function with($object){return $object;}
It's not a method, it's a stand-alone function. They claim it has something to do with chaining - is it compensating for some weird deficiency in PHP syntax where you can build an object or an expression in the argument to the function, but can't apply a method or operate on the result until you return it?
That's what I'm finally starting to suspect as I write this, but that's so weird I wonder if it's something else altogether that I'm missing.
Thanks - it's just been bothering me for years! I can't see why you would have to return an object from a function to chain it to another...
I would assume for the most part because (new Blah)->method() (Class member access on instantiation) wasn't added until PHP version 5.4.
Last time i checked (2008) annotations in php weren't so wide spread. Now after reading some material and having done some "googling", i am still a little confused. Could someone provide a minimal working example that illustrates how to use annotations in php:
Lets just say i want something like this to work:
class ClassName
{
/**
* #DefaultValue("test")
*/
public $prop;
}
// so that i can do
$kls = new ClassName();
$kls->prop // => test
I havent done php in a long while
UPDATE
The purpose of this question is to understand how libraries/frameworks like symfony,flow3 and doctrine implement their annotations.
Annotations are not (yet) supported by PHP. There is an RFC for a proposed implementation, but it's still unknown if or when would that happen.
The particular example that you've given might be interpreted by an IDE as a value to auto-complete and otherwise you can just do public $prop = 'Test';, but I guess you already know that and it's not your real intention.
In PHP Manual -> Function Reference Variable and Type Related Extensions -> Reflection, exists a method getDocComment() in several reflection classes (ReflectionClass, ReflectionMethod, ReflectionFunction, ReflectionFunctionAbstract, ReflectionProperty...) where you can get the doc comment block. Then process your comment the way you want. Example:
class Foo {
private $a;
private $b;
...
/**
* #annotation('baz')
*/
public function bar() {
...
}
}
$reflMethod = new ReflectionMethod('Foo', 'bar');
//prints
//string(26) "/**
// * #annotation('baz')
// */"
var_dump($reflMethod->getDocComment());
PHP Shouldn't support annotations, they're a scourge among PHP developers at the moment. They cause many problems:
They break version control. If you want two differently configured instances of an object in different projects they become different branches even though it's the configuration that's changed and not the logic.
They reduce portability. If you move a class around between two projects that use annotations, the annotations may break the second project
They break encapsulation. The application code shouldn't be concerned with how it will be used externally. Annotations tell the client code what it should be doing rather than letting the client code decide. In your #DefaultValue example, what if you use the class somewhere that isn't paying attention to the annotation? Will the class work anyway if the default value hasn't been set? Yes? No? Maybe? Whatever the answer, it's not clear in the API and there's no way to know whether the object, once constructed is ready to fulfil its responsibilities.
They limit flexibility. Using Symfony's #Inject as an example, it's impossible to create two instances of the class with different injected parameters .
See: Annotations are an abomination and PHP Annotations Are a Horrible Idea for a more detailed explanation of why they should be avoided.
PHP doesn't support annotations (yet).
The only place I've used annotations in PHP that affect code flow is in phpUnit, which supports a number of annotation markers (eg #DataProvider and #ExpectedException) for handling various aspects of the test script.
That works fairly well, but isn't handled by PHP natively; phpUnit has to parse the script itself before including it and running the code normally. Fair enough for a unit test script, but not an ideal solution for a production system.
So I think the real answer is that you'll have to wait until PHP implements annotations natively. I believe there's a proposal for it, but it certainly isn't going to happen any time soon -- it's definitely not going to be in 5.5, which will be released next year. I don't think there are any fixed plans for the features in 5.6 or beyond, but if we're stretching out into at least 2014 for that, even assuming your hosting provider or server admins are willing to upgrade immediately.
Yes, PHP doesn't support annotations yet, but we can rather use Doctrine Annotations. Have a look - https://www.doctrine-project.org/projects/annotations.html
I've built a ZF app using 1.10 for deployment on RHEL server in a corporate client, which has PHP 5.1.6. It won't run.
I googled and now realise it's the version of PHP. I didn't realise ZF had a minimum requirement for PHP 5.2.4, and calls to HeadLink seem to be causing fatal error "Call to undefined method Zend_View_Helper_Placeholder_Container::ksort()":
PHP Fatal error: Call to undefined method Zend_View_Helper_Placeholder_Container::ksort() in /library/ Zend/View/Helper/HeadLink.php on line 321
The client won't upgrade their PHP; I don't want to rewrite the app without ZF, and I'd rather not downgrade ZF to a grossly earlier version.
Is there some patch I can use to add ksort() to ZF 1.10 to get around this? There may be other problems, but this is where I'm stuck right now.
Any advice welcome
Many thanks
Ian
EDIT: As I say in a comment below, I expect many people have hit this before and will keep on doing so as RHEL5 will be a standard in corporate environments for a good time to come. I was hoping for a link to an existing solution rather having to devise one from scratch.
UPDATE: I used the patch linked to in the accepted answer and it fixed the problem for me.
This is adding the following public method to Zend/View/Helper/Placeholder/Container/Abstract.php
/**
* Sort the array by key
*
* #return array
*/
public function ksort()
{
$items = $this->getArrayCopy();
return ksort($items);
}
There was one remaining issue; a PHP notice caused by a string conversion in Zend_View_Helper_Doctype. Comparing this function to similar ones above and below, this seems to be an error in the library
public function isHtml5() {
return (stristr($this->doctype(), '<!DOCTYPE html>') ? true : false);
}
Changed to:
public function isHtml5() {
return (stristr($this->getDoctype(), '<!DOCTYPE html>') ? true : false);
}
Patching the library itself was the last thing I would normally do, but in this case it got me out of a spot. We'll make sure the patch is versioned in the repo and documented obviously for future developers.
I had the same issue today.
I found solution in this blog post.
Add the following snippet in /Zend/View/Helper/Placeholder/Container/Abstract.php:
/**
* Sort the array by key
*
* #return array
*/
public function ksort()
{
$items = $this->getArrayCopy();
return ksort($items);
}
I suppose you could change the inheritance of Zend_View_Helper_Placeholder_Container or Zend_View_Helper_Placeholder_Container_Abstract to supply your own implementation of ArrayObject::ksort. Something like:
class CompatibilityArrayObject extends ArrayObject {
public function ksort () {
// here be dragons
}
}
abstract class Zend_View_Helper_Placeholder_Container_Abstract
extends CompatibilityArrayObject {
...
}
You don't know how many more problems there are though. If the requirement says PHP 5.2.4, that's what you should run it on.
I'm looking to create an on-site API reference for my framework and application.
Basically, say I have a class file model.class.php:
class Model extends Object {
... code here ...
// Separates results into pages.
// Returns Paginator object.
final public function paginate($perpage = 10) {
... more code here ...
}
}
and I want to be able to generate a reference that my developers can refer to quickly in order to know which functions are available to be called. They only need to see the comments directly above each function and the declaration line. Something like this (similar to a C++ header file):
// Separates results into pages.
// Returns Paginator object.
final public function paginate($perpage = 10);
I've done some research and this answer looked pretty good (using Reflection classes), however, I'm not sure how I can keep the comments in.
Any ideas?
I want to keep the current comment formatting. Myself and the people who are working on the code hate the verbosity associated with PHPDocumentor. Not to mention a comment-rewrite of the entire project would take years, so I want to preserve just the // comments in plaintext.
Why don't you just run PHPDocumenter on the code?
PHPDoc is identical to JavaDoc, and will retain all the parameters and comments in the docblock above the function.
EDIT: Since you don't want PHPDoc, I think it would probably be easiest to write a RegEx parser to do it, since Reflection won't provide you with any surrounding comments.
PHP code to get the comment:
if(preg_match("#//(.+)$#",$line,$match)>0)
{
echo "Comment is: ".$match[1];
}
this is what phpdoc is for. you comment your code a specific way, following certain rules, and when you're done you run your code through a parser. It outputs exactly what you're looking for.