13 posts tagged with "php"
View All Tags一次tcp错误排查
一个使用php的workman的代码抛出了这样的异常
fwrite(): send of 157 bytes failed with errno=11 Resource temporarily unavailable
socket是使用了noblocking的,结果有一个这个错误,结果发现是已经修复了不抛异常了,但是在我的php5.6的版本还是旧的代码,所以还是会抛这个异常,所以排查了一天,不是bug 最新的修改
https://github.com/php/php-src/pull/5026/files
didwrite = send(sock->socket, buf, XP_SOCK_BUF_SIZE(count), (sock->is_blocked && ptimeout) ? MSG_DONTWAIT : 0);
if (didwrite <= 0) {
char *estr;
int err = php_socket_errno();
if (err == EWOULDBLOCK || err == EAGAIN) {
if (sock->is_blocked) {
int retval;
sock->timeout_event = 0;
do {
retval = php_pollfd_for(sock->socket, POLLOUT, ptimeout);
if (retval == 0) {
sock->timeout_event = 1;
break;
}
if (retval > 0) {
/* writable now; retry */
goto retry;
}
err = php_socket_errno();
} while (err == EINTR);
} else {
/* EWOULDBLOCK/EAGAIN is not an error for a non-blocking stream.
* Report zero byte write instead. */
return 0;
}
}
estr = php_socket_strerror(err, NULL, 0);
php_error_docref(NULL, E_NOTICE, "Send of " ZEND_LONG_FMT " bytes failed with errno=%d %s",
(zend_long)count, err, estr);
efree(estr);
}
if (didwrite > 0) {
php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), didwrite, 0);
}
return didwrite;
}
php opcode to handler
php 的opcode 对应很多的handler
选哪个handler 是怎么选择的呢?
和tcp协议一个连接 是一个五元组一样
php的opcode 的handler 是一个三元组
分别是 opcode
, op1
, op2
核心函数
ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler(zend_op* op)
{
zend_uchar opcode = zend_user_opcodes[op->opcode];
...
// zend_opcode_handlers 是什么呢? 是一堆函数指针的数组 ,每个opcode + op1+ op2 决定一个 函数指针
op->handler = zend_opcode_handlers[zend_vm_get_opcode_handler_idx(zend_spec_handlers[opcode], op)];
}
所以核心的核心就是
zend_vm_get_opcode_handler_idx(zend_spec_handlers[opcode], op)
他做了什么呢? 其实就是算出zend_opcode_handlers这个函数指针数组的偏移值
coding
我很蠢,什么都不会,代码也不会写
我只是喜欢一个我不存在的东西
我觉得写工作的代码很恶心
但是我喜欢修bug
最近最开心的是给php-src
提了两个pr并且通过了 ,但是我还是不会写php,我也不会c,我也背不过php的array系列的函数.
说到底,我还是太弱了
我其实不会写代码,但是会修bug.
因为修bug是体力活,写代码是脑力活
我果然很笨,什么都不会 只会写一堆bug
准备看看能不能修mysql的代码
没有银弹 No Silver Bullet
我真的会写代码吗? 我其实什么都不懂吧
我真的什么都不懂,有点怀疑自己这几年是不是只会copy and plaste 了
php 反射
反射是一个很特别的api,php的反射是一个很特别的回调
(gdb) bt
#0 zim_reflection_class_hasProperty (execute_data=0x7ffff3a14220, return_value=0x7ffff3a14180) at /home/ubuntu/php-src-php-7.4.1/ext/reflection/php_reflection.c:4186
#1 0x0000555555af49b2 in ZEND_DO_FCALL_SPEC_RETVAL_USED_HANDLER () at /home/ubuntu/php-src-php-7.4.1/Zend/zend_vm_execute.h:1729
#2 0x0000555555b58295 in execute_ex (ex=0x7ffff3a14020) at /home/ubuntu/php-src-php-7.4.1/Zend/zend_vm_execute.h:53588
#3 0x0000555555b5c32d in zend_execute (op_array=0x7ffff3a61c00, return_value=0x0) at /home/ubuntu/php-src-php-7.4.1/Zend/zend_vm_execute.h:57664
#4 0x0000555555a80b27 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/ubuntu/php-src-php-7.4.1/Zend/zend.c:1663
#5 0x00005555559e2bad in php_execute_script (primary_file=0x7fffffffd0e0) at /home/ubuntu/php-src-php-7.4.1/main/main.c:2619
#6 0x0000555555b5ee34 in do_cli (argc=2, argv=0x55555678ab30) at /home/ubuntu/php-src-php-7.4.1/sapi/cli/php_cli.c:961
#7 0x0000555555b5ff9e in main (argc=2, argv=0x55555678ab30) at /home/ubuntu/php-src-php-7.4.1/sapi/cli/php_cli.c:1352
php pdo 相关参数
thinkphp5 的默认配置会开启ERRMODE_EXCEPTION
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
pdo实现
pdo 的raise_impl_error
会根据配置判断是否需要抛出异常,当设置成PDO::ERRMODE_EXCEPTION
,则可以需要抛出异常
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp) /* {{{ */
{
...
if (dbh && dbh->error_mode != PDO_ERRMODE_EXCEPTION) { // 没有设置 ERRMODE_EXCEPTION则抛warning
php_error_docref(NULL, E_WARNING, "%s", message);
} else {
zval ex, info;
zend_class_entry *def_ex = php_pdo_get_exception_base(1), *pdo_ex = php_pdo_get_exception();
object_init_ex(&ex, pdo_ex);
zend_update_property_string(def_ex, &ex, "message", sizeof("message")-1, message);
zend_update_property_string(def_ex, &ex, "code", sizeof("code")-1, *pdo_err);
array_init(&info);
add_next_index_string(&info, *pdo_err);
add_next_index_long(&info, 0);
zend_update_property(pdo_ex, &ex, "errorInfo", sizeof("errorInfo")-1, &info);
zval_ptr_dtor(&info);
zend_throw_exception_object(&ex); // // 否则抛出异常
}
if (message) {
efree(message);
}
}
所以sql相关的错误只要try_catch还是能catch不少的
php-cgi-windows-curl
协程切换
Breakpoint 2, 0x00007fffedb6c090 in swoole::Context::Context(unsigned long, void (*)(void*), void*)@plt ()
from /usr/local/phpfork/lib/php/extensions/debug-non-zts-20170718/swoole.so
(gdb) bt
#0 0x00007fffedb6c090 in swoole::Context::Context(unsigned long, void (*)(void*), void*)@plt ()
from /usr/local/phpfork/lib/php/extensions/debug-non-zts-20170718/swoole.so
#1 0x00007fffedc207b1 in swoole::Coroutine::Coroutine (this=0x17a8540, fn=0x7fffedc1cdb2 <swoole::PHPCoroutine::main_func(void*)>, private_data=0x7fffffffa0a0)
at /home/dinosaur/swoole-src/include/coroutine.h:204
#2 0x00007fffedc205ee in swoole::Coroutine::create (fn=0x7fffedc1cdb2 <swoole::PHPCoroutine::main_func(void*)>, args=0x7fffffffa0a0)
at /home/dinosaur/swoole-src/include/coroutine.h:121
#3 0x00007fffedc1d7d0 in swoole::PHPCoroutine::create (fci_cache=0x7fffffffa140, argc=0, argv=0x0) at /home/dinosaur/swoole-src/swoole_coroutine.cc:857
#4 0x00007fffedc1eebd in zif_swoole_coroutine_create (execute_data=0x7fffef61e090, return_value=0x7fffffffa1e0)
at /home/dinosaur/swoole-src/swoole_coroutine.cc:964
#5 0x0000000000aaf137 in ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_HANDLER () at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:738
#6 0x0000000000b42992 in execute_ex (ex=0x7fffef61e030) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:59743
#7 0x0000000000b47d9d in zend_execute (op_array=0x7fffef684b00, return_value=0x0) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:63760
#8 0x0000000000a3afe0 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend.c:1496
#9 0x000000000098c749 in php_execute_script (primary_file=0x7fffffffc8c0) at /home/dinosaur/Downloads/php-7.2.2/main/main.c:2590
#10 0x0000000000b4b2a5 in do_cli (argc=2, argv=0x1561f20) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1011
#11 0x0000000000b4c491 in main (argc=2, argv=0x1561f20) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1404
php tokenlizer与php-cs-fixer
tokenlizer
代码:
<?php
$code = '<?php echo "string1"."string2"; >';
$tokens = token_get_all($code);
foreach ($tokens as $token) {
if (is_array($token)) {
// 行号、标识符字面量、对应内容
printf("%d - %s\t%s\n", $token[2], token_name($token[0]), $token[1]);
}
}
输出内容:
1 - T_OPEN_TAG <?php
1 - T_ECHO echo
1 - T_WHITESPACE
1 - T_CONSTANT_ENCAPSED_STRING "string1"
1 - T_CONSTANT_ENCAPSED_STRING "string2"
1 - T_WHITESPACE
php-cs-fixer
php-cs-fixer的核心函数是:token_get_all
$tokens = \defined('TOKEN_PARSE')
? token_get_all($code, TOKEN_PARSE)
: token_get_all($code);
调用的核心堆栈:
#0 E:\PHP-CS-Fixer\src\Tokenizer\Tokens.php(222): PhpCsFixer\Tokenizer\Tokens->setCode('<?php\n\n/*\n * Th...')
#1 E:\PHP-CS-Fixer\src\Runner\Runner.php(171): PhpCsFixer\Tokenizer\Tokens::fromCode('<?php\n\n/*\n * Th...')
#2 E:\PHP-CS-Fixer\src\Runner\Runner.php(132): PhpCsFixer\Runner\Runner->fixFile(Object(SplFileInfo), Object(PhpCsFixer\Linter\ProcessLintingResult))
#3 E:\PHP-CS-Fixer\src\Console\Command\FixCommand.php(219): PhpCsFixer\Runner\Runner->fix()
#4 E:\PHP-CS-Fixer\vendor\symfony\console\Command\Command.php(255): PhpCsFixer\Console\Command\FixCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#5 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(982): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#6 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(255): Symfony\Component\Console\Application->doRunCommand(Object(PhpCsFixer\Console\Command\FixCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#7 E:\PHP-CS-Fixer\src\Console\Application.php(84): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#8 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(148): PhpCsFixer\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#9 E:\PHP-CS-Fixer\php-cs-fixer(101): Symfony\Component\Console\Application->run()
#10 {main}
举个例子下面的堆栈:
#0 E:\PHP-CS-Fixer\src\Fixer\Operator\BinaryOperatorSpacesFixer.php(339): PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer->fixWhiteSpaceAroundOperatorToSingleSpace(Object(PhpCsFixer\Tokenizer\Tokens), 19)
#1 E:\PHP-CS-Fixer\src\Fixer\Operator\BinaryOperatorSpacesFixer.php(256): PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer->fixWhiteSpaceAroundOperator(Object(PhpCsFixer\Tokenizer\Tokens), 19)
#2 E:\PHP-CS-Fixer\src\AbstractFixer.php(75): PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer->applyFix(Object(SplFileInfo), Object(PhpCsFixer\Tokenizer\Tokens))
#3 E:\PHP-CS-Fixer\src\Runner\Runner.php(192): PhpCsFixer\AbstractFixer->fix(Object(SplFileInfo), Object(PhpCsFixer\Tokenizer\Tokens))
#4 E:\PHP-CS-Fixer\src\Runner\Runner.php(132): PhpCsFixer\Runner\Runner->fixFile(Object(SplFileInfo), Object(PhpCsFixer\Linter\ProcessLintingResult))
#5 E:\PHP-CS-Fixer\src\Console\Command\FixCommand.php(219): PhpCsFixer\Runner\Runner->fix()
#6 E:\PHP-CS-Fixer\vendor\symfony\console\Command\Command.php(255): PhpCsFixer\Console\Command\FixCommand->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#7 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(982): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#8 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(255): Symfony\Component\Console\Application->doRunCommand(Object(PhpCsFixer\Console\Command\FixCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#9 E:\PHP-CS-Fixer\src\Console\Application.php(84): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#10 E:\PHP-CS-Fixer\vendor\symfony\console\Application.php(148): PhpCsFixer\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#11 E:\PHP-CS-Fixer\php-cs-fixer(101): Symfony\Component\Console\Application->run()
#12 {main}
核心就是给后面加入token // todo
composer-ext
看到phpstorm的相关警告,经常会看到phpstorm会警告没有ext-json
,我才最近发现composer.json会添加相关的扩展校验.
举个例子
"require": {
"php": ">=5.4.0",
"topthink/framework": "^5.0",
"php-imap/php-imap": "~2.0",
"phpoffice/phpspreadsheet": "^1.3",
"hprose/hprose": "^2.0",
"ext-json": "*" // 这就是解析require json 扩展
},
这个就是校验是否含有json
扩展,那么composer是怎么实现的呢?其实是通过extension_loaded
这个函数取查看扩展版本的
实现是在composer的129行实现,通过extension_loaded
获取扩展.