Skip to main content

12 posts tagged with "php"

View All Tags

· 3 min read

function()

1.生成代码

cd php_src/ext/
./ext_skel --extname=say

cd ..
vi ext/say/config.m4
./buildconf
./configure --[with|enable]-say
make
./sapi/cli/php -f ext/say/say.php
vi ext/say/say.c
make

2.修改config.m4配置文件

dnl If your extension references something external, use with:

dnl PHP_ARG_WITH(say, for say support,
dnl Make sure that the comment is aligned:
dnl [ --with-say Include say support])

dnl Otherwise use enable:

PHP_ARG_ENABLE(say, whether to enable say support,
Make sure that the comment is aligned:
[ --enable-say Enable say support])

3.代码实现

修改say.c文件。实现say方法。
找到PHP_FUNCTION(confirm_say_compiled),在其上面增加如下代码:
PHP_FUNCTION(say)
{
zend_string *strg;
strg = strpprintf(0, "hello word");
RETURN_STR(strg);
}

找到 PHP_FE(confirm_say_compiled, 在上面增加如下代码:
PHP_FE(say, NULL)

修改后的代码如下:
const zend_function_entry say_functions[] = {
PHP_FE(say, NULL)
PHP_FE(confirm_say_compiled, NULL) /* For testing, remove later. */
PHP_FE_END /* Must be the last line in say_functions[] */
};

4.编译安装

编译扩展的步骤如下:
phpize
./configure
make && make install

修改php.ini文件,增加如下代码:
[say]
extension = say.so

然后执行,php -m 命令。在输出的内容中,你会看到say字样。

function(...arg)

test.php

<?php
function default_value ($type, $value = null) {
if ($type == "int") {
return $value ?? 0;
} else if ($type == "bool") {
return $value ?? false;
} else if ($type == "str") {
return is_null($value) ? "" : $value;
}
return null;
}

var_dump(default_value("int"));
var_dump(default_value("int", 1));
var_dump(default_value("bool"));
var_dump(default_value("bool", true));
var_dump(default_value("str"));
var_dump(default_value("str", "a"));
var_dump(default_value("array"));
?>

say.c

PHP_FUNCTION(default_value)
{
zend_string *type;
zval *value = NULL;

#ifndef FAST_ZPP
/* Get function parameters and do error-checking. */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &type, &value) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(type)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL_EX(value, 0, 1)
ZEND_PARSE_PARAMETERS_END();
#endif

if (ZSTR_LEN(type) == 3 && strncmp(ZSTR_VAL(type), "int", 3) == 0 && value == NULL) {
RETURN_LONG(0);
} else if (ZSTR_LEN(type) == 3 && strncmp(ZSTR_VAL(type), "int", 3) == 0 && value != NULL) {
RETURN_ZVAL(value, 0, 1);
} else if (ZSTR_LEN(type) == 4 && strncmp(ZSTR_VAL(type), "bool", 4) == 0 && value == NULL) {
RETURN_FALSE;
} else if (ZSTR_LEN(type) == 4 && strncmp(ZSTR_VAL(type), "bool", 4) == 0 && value != NULL) {
RETURN_ZVAL(value, 0, 1);
} else if (ZSTR_LEN(type) == 3 && strncmp(ZSTR_VAL(type), "str", 3) == 0 && value == NULL) {
RETURN_EMPTY_STRING();
} else if (ZSTR_LEN(type) == 3 && strncmp(ZSTR_VAL(type), "str", 3) == 0 && value != NULL) {
RETURN_ZVAL(value, 0, 1);
}
RETURN_NULL();
}

PHP_FE add PHP_FE(default_value, NULL)

· 2 min read
<?php

/**
* 命令行获取参数
* create by 赵煜杰
* lastmodify 2015年3月27日 14:42:36
* use A: php test.php --stdin="true"
* use B: php test.php --environ="online" --check="true"
*/
class cli_param
{
/**
* @param boolean $stdin
* true 支持手动输入
* false 不合法直接退出
*/
public $stdin;
public $filename;

public function __construct($filename = 'here', $stdin = false)
{
$this->start();
$this->filename = $filename;
$this->stdin = $stdin;
}

public function get($arr)
{
$return = [];
/** @var array $longopts */
$longopts = ['stdin:'];
foreach ($arr as $k => $v) {
$longopts[] = $k . ':';
}
$opts = getopt('', $longopts);
if (isset($opts['stdin']) && $opts['stdin'] == "true") {
$this->stdin = true;
}
unset($opts['stdin']);
if (count($opts) != count($arr)) {
foreach (array_keys($arr) as $v) {
$opts[$v] = isset($opts[$v]) ? $opts[$v] : '';
}
}
foreach ($opts as $k => $v) {
if (!in_array($v, $arr[$k]['param'])) {
if ($this->stdin) {
echo $arr[$k]['desc'] . "\n";
fwrite(STDOUT, "Enter Field '{$k}': ");
$get = trim(fgets(STDIN));
while (!in_array($get, $arr[$k]['param'])) {
if (isset($arr[$k]['desc'])) {
fwrite(STDOUT, "{$arr[$k]['desc']},\nit maybe in (" . implode(',', $arr[$k]['param']) . "): ");
} else {
fwrite(STDOUT, "Your Field '{$k}' is error,\nit maybe in (" . implode(',', $arr[$k]['param']) . "): ");
}
$get = trim(fgets(STDIN));
}
$return[$k] = $get;
} else {
echo "Parameter is error: Field '{$k}' not in (" . implode(',', $arr[$k]['param']) . ")\n";
$this->end();
}
} else {
$return[$k] = $v;
}
}

return $return;
}

public function start()
{
echo "Log from '" . $this->filename . "'\n";
echo "\n" . str_repeat('=', 79) . "\n";
}

public function end()
{
echo str_repeat('=', 79) . "\n\n";
exit;
}
}

cli类 使用

<?php
$arr = [
'environ' => [
'desc' => 'descdescdescdescdesc',
'param' => ['online', 'offline'],
],
'check' => [
'desc' => 'descdescdescdescdesc',
'param' => ['true', 'false'],
],
];
$a = (new cli_param(__FILE__, true))->get($arr);
print_r($a);

· One min read

你必须知道的 17 个 Composer 最佳实践 https://juejin.im/entry/5a72d506518825734501dd6d

代理

composer config -g repo.packagist composer https://packagist.phpcomposer.com

简化 bower

composer.json && composer fxp

{
"scripts": {
"fxp": [
"composer global require 'fxp/composer-asset-plugin'"
]
},
"config": {
"process-timeout": 1800,
"fxp-asset": {
"enabled": true,
"installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
}
}

装单个

composer update nothing

composer require league/oauth2-client --no-update
composer update league/oauth2-client

php composer.phar require --dev --prefer-dist yiisoft/yii2-gii

autoload 加速

composer dump-autoload --classmap-authoritative

· 8 min read

https://blog.csdn.net/CleverCode/article/details/53239681

<?php
/**
* 随机红包+固定红包算法[策略模式]
* copyright (c) 2016 http://blog.csdn.net/CleverCode
*/

//配置传输数据DTO
class OptionDTO
{

//红包总金额
public $totalMoney;

//红包数量
public $num;

//范围开始
public $rangeStart;

//范围结算
public $rangeEnd;

//生成红包策略
public $builderStrategy;

//随机红包剩余规则
public $randFormatType; //Can_Left:不修数据,可以有剩余;No_Left:不能有剩余

public static function create(
$totalMoney,
$num,
$rangeStart,
$rangEnd,
$builderStrategy,
$randFormatType = 'No_Left'
) {
$self = new self();
$self->num = $num;
$self->rangeStart = $rangeStart;
$self->rangeEnd = $rangEnd;
$self->totalMoney = $totalMoney;
$self->builderStrategy = $builderStrategy;
$self->randFormatType = $randFormatType;
return $self;
}

}

//红包生成器接口
interface IBuilderStrategy
{
//创建红包
public function create();

//设置配置
public function setOption(OptionDTO $option);

//是否可以生成红包
public function isCanBuilder();

//生成红包函数
public function fx($x);
}

//固定等额红包策略
class EqualPackageStrategy implements IBuilderStrategy
{
//单个红包金额
public $oneMoney;

//数量
public $num;

public function __construct($option = null)
{
if ($option instanceof OptionDTO) {
$this->setOption($option);
}
}

public function setOption(OptionDTO $option)
{
$this->oneMoney = $option->rangeStart;
$this->num = $option->num;
}

public function create()
{

$data = [];
if (false == $this->isCanBuilder()) {
return $data;
}

$data = [];
if (false == is_int($this->num) || $this->num <= 0) {
return $data;
}
for ($i = 1; $i <= $this->num; $i++) {
$data[$i] = $this->fx($i);
}
return $data;
}

/**
* 等额红包的方程是一条直线
* @param mixed $x
* @return mixed
*/
public function fx($x)
{
return $this->oneMoney;
}

/**
* 是否能固定红包
* @return mixed
*/
public function isCanBuilder()
{
if (false == is_int($this->num) || $this->num <= 0) {
return false;
}

if (false == is_numeric($this->oneMoney) || $this->oneMoney <= 0) {
return false;
}

//单个红包小于1分
if ($this->oneMoney < 0.01) {
return false;
}

return true;

}


}

//随机红包策略(三角形)
class RandTrianglePackageStrategy implements IBuilderStrategy
{
//总额
public $totalMoney;

//红包数量
public $num;

//随机红包最小值
public $minMoney;

//随机红包最大值
public $maxMoney;

//修数据方式:NO_LEFT: 红包总额 = 预算总额;CAN_LEFT: 红包总额 <= 预算总额
public $formatType;

//预算剩余金额
public $leftMoney;


public function __construct($option = null)
{
if ($option instanceof OptionDTO) {
$this->setOption($option);
}
}

public function setOption(OptionDTO $option)
{
$this->totalMoney = $option->totalMoney;
$this->num = $option->num;
$this->formatType = $option->randFormatType;
$this->minMoney = $option->rangeStart;
$this->maxMoney = $option->rangeEnd;
$this->leftMoney = $this->totalMoney;
}

/**
* 创建随机红包
* @return mixed
*/
public function create()
{

$data = [];
if (false == $this->isCanBuilder()) {
return $data;
}

$leftMoney = $this->leftMoney;
for ($i = 1; $i <= $this->num; $i++) {
$data[$i] = $this->fx($i);
$leftMoney = $leftMoney - $data[$i];
}

//修数据
list($okLeftMoney, $okData) = $this->format($leftMoney, $data);

//随机排序
shuffle($okData);
$this->leftMoney = $okLeftMoney;

return $okData;
}

/**
* 是否能够发随机红包
* @return mixed
*/
public function isCanBuilder()
{
if (false == is_int($this->num) || $this->num <= 0) {
return false;
}

if (false == is_numeric($this->totalMoney) || $this->totalMoney <= 0) {
return false;
}

//均值
$avgMoney = $this->totalMoney / 1.0 / $this->num;

//均值小于最小值
if ($avgMoney < $this->minMoney) {
return false;
}

return true;

}

/**
* 获取剩余金额
* @return mixed
*/
public function getLeftMoney()
{
return $this->leftMoney;
}

/**
* 随机红包生成函数。三角函数。[(1,0.01),($num/2,$avgMoney),($num,0.01)]
*
* @param mixed $x ,1 <= $x <= $this->num;
* @access public
* @return mixed
*/
public function fx($x)
{

if (false == $this->isCanBuilder()) {
return 0;
}

if ($x < 1 || $x > $this->num) {
return 0;
}

$x1 = 1;
$y1 = $this->minMoney;

//我的峰值
$y2 = $this->maxMoney;

//中间点
$x2 = ceil($this->num / 1.0 / 2);

//最后点
$x3 = $this->num;
$y3 = $this->minMoney;

//当x1,x2,x3都是1的时候(竖线)
if ($x1 == $x2 && $x2 == $x3) {
return $y2;
}

// '/_\'三角形状的线性方程
//'/'部分
if ($x1 != $x2 && $x >= $x1 && $x <= $x2) {

$y = 1.0 * ($x - $x1) / ($x2 - $x1) * ($y2 - $y1) + $y1;
return number_format($y, 2, '.', '');
}

//'\'形状
if ($x2 != $x3 && $x >= $x2 && $x <= $x3) {

$y = 1.0 * ($x - $x2) / ($x3 - $x2) * ($y3 - $y2) + $y2;
return number_format($y, 2, '.', '');
}

return 0;


}

/**
* 格式化修红包数据
* @param mixed $leftMoney
* @param array $data
* @return mixed
*/
private function format($leftMoney, array $data)
{

//不能发随机红包
if (false == $this->isCanBuilder()) {
return [$leftMoney, $data];
}

//红包剩余是0
if (0 == $leftMoney) {
return [$leftMoney, $data];
}

//数组为空
if (count($data) < 1) {
return [$leftMoney, $data];
}

//如果是可以有剩余,并且$leftMoney > 0
if ('Can_Left' == $this->formatType
&& $leftMoney > 0) {
return [$leftMoney, $data];
}


//我的峰值
$myMax = $this->maxMoney;

// 如果还有余钱,则尝试加到小红包里,如果加不进去,则尝试下一个。
while ($leftMoney > 0) {
$found = 0;
foreach ($data as $key => $val) {
//减少循环优化
if ($leftMoney <= 0) {
break;
}

//预判
$afterLeftMoney = (double)$leftMoney - 0.01;
$afterVal = (double)$val + 0.01;
if ($afterLeftMoney >= 0 && $afterVal <= $myMax) {
$found = 1;
$data[$key] = number_format($afterVal, 2, '.', '');
$leftMoney = $afterLeftMoney;
//精度
$leftMoney = number_format($leftMoney, 2, '.', '');
}
}

//如果没有可以加的红包,需要结束,否则死循环
if ($found == 0) {
break;
}
}
//如果$leftMoney < 0 ,说明生成的红包超过预算了,需要减少部分红包金额
while ($leftMoney < 0) {
$found = 0;
foreach ($data as $key => $val) {
if ($leftMoney >= 0) {
break;
}
//预判

$afterLeftMoney = (double)$leftMoney + 0.01;
$afterVal = (double)$val - 0.01;
if ($afterLeftMoney <= 0 && $afterVal >= $this->minMoney) {
$found = 1;
$data[$key] = number_format($afterVal, 2, '.', '');
$leftMoney = $afterLeftMoney;
$leftMoney = number_format($leftMoney, 2, '.', '');
}
}

//如果一个减少的红包都没有的话,需要结束,否则死循环
if ($found == 0) {
break;
}
}
return [$leftMoney, $data];
}

}

//维护策略的环境类
class RedPackageBuilder
{

// 实例
protected static $_instance = null;

/**
* Singleton instance(获取自己的实例)
*
* @return $this
*/
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}

/**
* 获取策略【使用反射】
* @param string $type 类型
* @return mixed
* @throws
*/
public function getBuilderStrategy($type)
{
$class = $type . 'PackageStrategy';

if (class_exists($class)) {
return new $class();
} else {
throw new Exception("{$class} 类不存在!");
}
}

public function getRedPackageByDTO(OptionDTO $optionDTO)
{
//获取策略
$builderStrategy = $this->getBuilderStrategy($optionDTO->builderStrategy);

//设置参数
$builderStrategy->setOption($optionDTO);

return $builderStrategy->create();
}

}

class Client
{
public static function main($argv)
{
//固定红包
// $totalMoney,$num,$rangeStart,$rangEnd,$builderStrategy,$randFormatType = 'No_Left'
// $dto = OptionDTO::create(1000,10,100,100,'Equal');
// $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
// print_r($data);

//随机红包[修数据]
// $dto = OptionDTO::create(400,150,2,4,'RandTriangle');
$dto = OptionDTO::create(240, 150, 1.1, 2.1, 'RandTriangle');
$data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
// print_r($data);
// sort($data);
// print_r($data);

foreach ($data as $key => &$value) {
$value *= 100;
echo $value . "\n";
}

echo array_sum($data);

//随机红包[不修数据]
$dto = OptionDTO::create(5, 10, 0.01, 0.99, 'RandTriangle', 'Can_Left');
$data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
// print_r($data);
}
}

Client::main($argv);

· One min read
开发模式下推荐,直接禁用opcache扩展更好

opcache.revalidate_freq=0
opcache.validate_timestamps=1
opcache.max_accelerated_files=3000
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1


多台机器集群模式或者代码更新频繁时推荐,可以兼顾性能,方便代码更新

opcache.revalidate_freq=300
opcache.validate_timestamps=1
opcache.max_accelerated_files=7963
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1


稳定项目推荐,性能最好

opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.max_accelerated_files=7963
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1

;other
opcache.huge_code_pages = 1
opcache.save_comments = 1

· One min read
;/usr/local/etc/php/php.ini
date.timezone = "Asia/Shanghai"

;opcache.md
opcache.revalidate_freq = 300
opcache.validate_timestamps = 1
opcache.max_accelerated_files = 7963
opcache.memory_consumption = 192
opcache.interned_strings_buffer = 16
opcache.fast_shutdown = 1
;other
opcache.huge_code_pages = 1
opcache.save_comments = 1

expose_php = Off

upload_max_filesize = 20m
post_max_size = 20m

www.conf

;/usr/local/etc/php-fpm.d/www.conf
pm = dynamic
pm.max_children = 100
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers = 50
pm.max_requests = 500

pm.max_children = $(($Mem/2/20)) 8g=200
pm.start_servers = $(($Mem/2/30)) 8g=150
pm.min_spare_servers = $(($Mem/2/40)) 8g=100
pm.max_spare_servers = $(($Mem/2/20)) 8g=200

· One min read

install

php codecept.phar bootstrap --namespace project1_tests
php codecept.phar bootstrap

/qr/tests/_bootstrap.php

require(__DIR__ . '../../aaaa/phpqrcode.php');

/qr/tests/unit.suite.yml

class_name: UnitTester
coverage:
enabled: true
white_list:
include:
- ../aaaa/*
exclude:
- ../tests/*
modules:
enabled:
- Asserts
- \project1_tests\Helper\Unit

run

php codecept.phar generate:test unit HelloWorld
php codecept.phar run unit HelloWorldTest
php codecept.phar run unit --coverage --coverage-html

· 2 min read

doc

内核系列

没分

.idea

#codeStyleSettings.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="RIGHT_MARGIN" value="200" />
<PHPCodeStyleSettings>
<option name="ALIGN_KEY_VALUE_PAIRS" value="true" />
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="true" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="BLANK_LINE_BEFORE_RETURN_STATEMENT" value="true" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
</PHPCodeStyleSettings>
<codeStyleSettings language="PHP">
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
</codeStyleSettings>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</component>
</project>

· 2 min read
<?php
function unicode_encode($name) {
$name = iconv('UTF-8', 'UCS-2', $name);
$len = strlen($name);
$str = '';
for ($i = 0; $i < $len - 1; $i = $i + 2) {
$c = $name[$i];
$c2 = $name[$i + 1];
if (ord($c) > 0) {// 两个字节的文字
$str .= '\u' . base_convert(ord($c), 10, 16) . base_convert(ord($c2), 10, 16);
} else {
$str .= $c2;
}
}
return $str;
}
$name = 'MY,你大爷的';
$unicode_name = unicode_encode($name);
echo '<h3>' . $unicode_name . '</h3>';
// 将UNICODE编码后的内容进行解码
function unicode_decode($name) {
// 转换编码,将Unicode编码转换成可以浏览的utf-8编码
$pattern = '/([\w]+)|(\\\u([\w]{4}))/i';
preg_match_all($pattern, $name, $matches);
if (!empty($matches)) {
$name = '';
for ($j = 0; $j < count($matches[0]); $j++) {
$str = $matches[0][$j];
if (strpos($str, '\\u') === 0) {
$code = base_convert(substr($str, 2, 2), 16, 10);
$code2 = base_convert(substr($str, 4), 16, 10);
$c = chr($code) . chr($code2);
$c = iconv('UCS-2', 'UTF-8', $c);
$name .= $c;
} else {
$name .= $str;
}
}
}
return $name;
}
echo 'MY,\u4f60\u5927\u7237\u7684 -> ' . unicode_decode($unicode_name);
?>

· One min read

PHPSTORM setting

  • Language php Debug => Xdebug port 9001
  • Language php Debug/DBGp => port:901 #项目的port
  • Language php Servers => Name:server-def, Host:0.0.0.0:901, Port:901, 右边map:/www # 项目文件夹
      environment:
PHP_IDE_CONFIG: "serverName=server-def"
volumes:
- ./__cicd__/php/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
[xdebug]
;./__cicd__/php/xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
zend_extension = /usr/local/lib/php/extensions/no-debug-non-zts-20160303/xdebug.so
xdebug.remote_handler = dbgp
xdebug.remote_port = 9001
xdebug.remote_host = 192.168.1.203
xdebug.remote_enable = 1
xdebug.remote_connect_back = 0
xdebug.profiler_enable = 1
xdebug.idekey = PHPSTORM
xdebug.remote_log = "/tmp/xdebug.log"