I was programming an application using php and pthreads and I noticed that it was't working correctly. In order to isolate the error I reduced the code, and now I have this piece of code, and I've checked that it behaves differently when executes it through the console than trought a web browser, and I can't find why, I'm here for help. The code is:
<?php
echo "beforethread<br/>";
class AsyncOperation extends Thread
{
private $sum;
public function __construct()
{
$this->sum = 5;
}
public function run()
{
echo "insidethread<br/>";
}
}
$thread = new AsyncOperation();
$thread->start();
$thread->join();
?>
through console I get:
beforethread
insidethread
and through a web browser:
insidethread
beforethread
I can't understand if php executes line by line why through web browser the code doesn't behave correctly. Any help will be appreciated. Thank you.
You should not write standard output in a web environment from any thread other than the one responding to the request. This is not safe, at least you will experience garbled output and at worst segmentation faults (since you are filling the buffer for stdout from another thread, which is not allowed, zend provides no way to abstract this).
Even at the console, if you want to make sense of your output you should use a mutex when writing to stdout.
Related
I've been using this method for years, and I've never run into an issue; however, it's always sort of nagged at me as to whether or not this is good practice. I'll cover what I'm doing specifically first and then provide background to the reasoning after since I'm sure it will be questioned.
Problem / Question
I am using file_get_contents to retrieve the contents of the very script that is running. In essence:
<?php
/**
* My PHP Script On Load
* Version: 1.0.0
*/
class MyClass {
public function __construct() {
$matches = array();
if (preg_match('Version\: ([0-9\.]+)/s', file_get_contents(__FILE__), $matches)) {
$version = $matches[1];
}
}
}
$class = new MyClass();
The above works, and out of thousands of page loads of my own use (and many tens of thousands of never hearing of errors that could stem from this), I've never had a problem doing this. I've just always wondered if either a) it's bad practice, or b) it has the possibility of causing an error.
Background / Use-case
Naturally the first question is going to be "Why don't you just put the version in the constructor?" Of course, I could, but I must have the plugin version at the top of the file in the comments as shown and the only reason I don't do that is so I don't have the possibility of forgetting to update one or the other. By having it one place, I never have to worry about a screw up, which if it made it to a release build, could cause major problems with the update system of the platform I'm working on.
I'm open to other ideas for how to approach this, aside from using a deployment/CI to automate the placement of the version number, which I've already considered and may implement at some point. But three things must be true: 1) the version must be commented out at the top of the file in the same format shown in the example, 2) I must be able to have version available to the PHP code within the very same file, 3) the class must be instantiated from within the same file.
There is a PHP function to retrieve just the comments: ReflectionClass::getDocComment. You can use it instead of reading the whole file. I'm not sure about how it works when the code is encoded as mentioned by #Iłya Bursov.
<?php
/**
* My PHP Script On Load
* Version: 1.0.0
*/
class MyClass {
public function __construct() {
$matches = array();
if (preg_match('/Version\: ([0-9\.]+)/s', (new ReflectionClass(__CLASS__))->getDocComment(), $matches)) {
$version = $matches[1];
}
}
}
$class = new MyClass();
?>
As soon as it is open ended question, just some thoughts:
for some projects php files must be encoded, for example with zend guard, this will break this scheme completely
reading whole file is not ideal, you can just read first 100-200 bytes of it instead
what about pre-processing before you upload to server? some script, which reads all files, comments and puts variable $version into class?
In code igniter web application we can can the controller and methods like domain-name/controller/method_name.Is there any way to access core PHP class methods like the same way?
How can i access the method in browser like domain/car/hello
The Car.php file is in the server root xampp/htdocs/Car.php
My class file Car.php:-
class Car{
public function hello()
{
echo 'Hello';
}
}
Please help.
You don't. The browser talks to the server (to PHP) using HTTP. HTTP has absolutely no notion of functions, or even what a programming language is. PHP also has no mechanism to allow anything to directly access/call a function from outside. The only thing that happens is that the web server decides based on the requested URL which PHP script to execute. That's all. Execution will always start on the first line of the script being executed, not directly in a function somewhere.
You can/have to write code which inspects the requested URL or otherwise decides which function to call, and then call it in PHP code.
Php is a server-side programming language, you simply cannot execute it in your browser without HTTP Server.
Upd: if you mean how can you run it in xaamp then you should run it. Run this by calling file like simple url page, for example localhost/Car.php
Try something like this:
<?php
Car $car = new Car();
$car->hello();
class Car{
public function hello(){
echo 'Hello';
}
}
I'm trying to write PHPUnit tests for a class that writes to error_log but seem to be having trouble with PHPUnit's output buffering.
Because of the potential volatility of error_log given an unknown SUT php.ini configuration, I ultimately decided upon writing to stdout after having limited success with overloading via namespace.
Unfortunately, there appears to be some quirk in how PHPUnit is buffering output in that calling expectOutputString returns an empty string as "Actual" rather than what was written to stdout.
Here's a quick-and-dirty test class I wrote to eliminate anything that might be giving me unintended grief ("ObTest.php"):
<?php
namespace Some\Test;
class ObTest
{
public function writeToErrorLog($message)
{
error_log($message);
}
}
And here's the test I wrote:
<?php
namespace Some\Test;
include "ObTest.php";
class ObTestTest extends \PHPUnit_Framework_TestCase
{
public static $error_log_config;
public static function setUpBeforeClass()
{
self::$error_log_config = ini_get("error_log");
ini_set("error_log", "/dev/stdout");
}
public static function tearDownAfterClass()
{
ini_set("error_log", self::$error_log_config);
}
public function testWriteToErrorLogOutputs()
{
$ob_test = new ObTest();
$this->expectOutputString("Test");
$ob_test->writeToErrorLog("Test");
}
}
And finally the output:
PHPUnit 5.4-g9b5b99b by Sebastian Bergmann and contributors.
[06-May-2016 01:05:51 UTC] Test
Failed asserting that two strings are equal.
Expected :'Test'
Actual :''
Note that I do realize that the test will fail anyway due to the timestamp, but writing a test with expectOutputRegex is unnecessary to demonstrate the blank string being returned as "Actual"; I can confirm that I get the same result using the regex option.
I'm running PHP 5.6.20-1+deb.sury.org~trusty+1 if it's relevant.
Update 2016-05-22
Per the comments, I have tried several variants of setting error_log to write to output, including the STDOUT constant and php://output stream, all with no success.
For anyone interested or encountering a similar issue, I also have since logged an issue on GitHub thinking that this may be some sort of bug, but it hasn't yet received any attention as of this update. The issue notes that I've also tried this on the latest stable PHPUnit version (5.3.2) without success.
I am new to PHP, and working on a class based web site. So my question is simple. Can I compile the site like I can in .NET?
This would be helpful to me because I changed my IsAAction interface to accept an error callback function as a parameter of the Execute function, and I would like all of my implementations to break so I can easily see where to change them.
Thanks in advance.
PHP can be compiled, as in you can compile it to machine code and prevent a parsing everytime you access a file. That the way accelerator like APC work. But you can't compile it like a .NET DLL with every error checked in advance. It would go against its dynamic nature. Late binding mean it will always check for error at runtime
For your particuliar problem, I would suggest adding Unit Tests to your project. They are very good to have anyway, and they will help you catch error in your interface implementation. I personally couldn't live without them. You may want to check PHPUnit or SimpleTests.
EDIT To understand why PHP can't check your error, just check this snippet of code.
if ($_GET['impl'] == 'interface1') {
interface MyInterface {
function foo($var);
}
} else {
interface MyInterface {
function bar($var, $var2);
}
}
class Implementation implements MyInterface { //Will crash or not depending on the URL!
function foo($var) {}
}
Yes and no. See:
Can you "compile" PHP code?
And:
http://www.phpcompiler.org/
And:
http://www.scriptol.com/apollo.php
https://github.com/facebook/hiphop-php/wiki - although I'm sure there are other answers on here that you'd find useful.
There's a opened topic on stackoverflow that is related.
Can you “compile” PHP code?
Some parties such as Facebook rewrote PHP runtime, or part of it so they make it possible to run compiled php code or other source codes, pretty much whatever you like.
HipHop for PHP
Its not an easy task. But you can do it.
Not to my knowledge. PHP is a script language.
I am writing a SOAP server and have hit a strange problem.
Here's the relevant lines from the server.php
class MyHandler {
public function __construct() { ... }
public function __wakeup() { ... }
public function getPrice() { ... }
}
$server = new SoapServer("my.wsdl", array("soap_version" => SOAP_1_2));
$server->setClass('MyHandler');
$server->addFunction("getPrice");
$server->handle();
Testing this locally (on PHP 5.3) works fine and I'm able to send requests and receive responses.
When I put this onto my development server (PHP 5.2.9), I get this error message:
SoapServer::addFunction(): Tried to add a non existant function 'getPrice'
Apart from the fact that they can't spell, this is very confusing.
I've since managed to work around the issue by changing the addFunction() line to this:
$server->addFunction(SOAP_FUNCTIONS_ALL);
... and it works fine! Of course, examining $server->getFunctions() shows that this adds the __construct() and __wakeup() functions from my class too, which doesn't seem like such a good thing.
What did I do wrong? Is the carpet bomb "add all functions" approach the only way here?
Using addFunction() tells it to look for a function named getPrice() on its own, outside of a class. This doesn't exist, so is causing the error.
Using addClass() will automatically add all the functions from MyHandler, so you shouldn't need to call addFunction(), getPrice() should have already been added.
Additionally, there's an open ticket (for PHP 5.2.9) on bugs.php.net which seems to indicate that there's no way of adding a class method using addFunction(): http://bugs.php.net/bug.php?id=47919
I don't have access to PHP 5.3 though, so not sure how things may have changed I'm afraid...
$server->addFunction(array("SOAPMethods", "getPrice"));
Hmm, not sure why it's working on PHP 5.3, but from what I understand, SoapServer::setClass() exports all the methods in the given class (ie, your getPrice() method will be exported using that).
SoapServer::addFunction() works specifically with, well functions. Any chance you had a stray getPrice() function lying around in your local environment?
You can test this with commenting out the addFunction() call which should still show your exported methods from "MyHandler".
Using SOAP_FUNCTIONS_ALL is probably a bad idea, as if you remove the setClass() call it actually exports all PHP functions for some reason...
I am using PHP version 5.3.10 and I had the same problem. And I solved it by adding array keyword.
Before:
$server->addFunction("functionName");
After:
$server->addFunction(array("functionName"));
Reference: PHP SoapServer::addFunction documentation.