hyperf 二十九 修改器 二

2024-04-12 19:20
文章标签 hyperf 二十九 修改器

本文主要是介绍hyperf 二十九 修改器 二,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

教程:Hyperf

属性类型转换
Hyperf\Database\Model\Concerns\HasAttributes::casts被HasAttributes::setAttribute()、HasAttributes::getAttribute()调用,执行类型转换。
HasAttributes::casts为数组类型可设置基本类型或类的实例。默认设置主键id为int。
内置的基本强制转换类型:

  • json:'array', 'json', 'object', 'collection'
  • 日期:'date', 'datetime'
  • 整数:'int'\integer
  • 浮点数: real\float\double
  • 数字:decimal
  • 字符串:string
  • 布尔:bool/boolean
  • 自定义时间:custom_datetime
  • 时间戳:timestamp

decimal 可设置小数位数,格式decimal:小数位数,通过number_format()实现。

一 自定义类型转换

通过继承接口(implements)Hyperf\Contract\CastsAttributes,定义好后使用其类名称将其附加到HasAttributes::casts。

1.1 值对象类型转换

将值转换成对象。通过get()获取时设置为对象、set()设置时将值设置到对象中。

执行save()之前需要设置相应的对象。官网例子中是先获取在设置,这样获取之后数据结构中自带类。

更改数据结构中类对象值后,因为缓存原因,其类的值不会通过HasAttributes::getAttributes()获得刷新,使用HasAttributes::syncAttributes()通过缓存和属性值合并可获取设置后的更新数据。

1.2 入站类型转换

设置set()实现入站类型转换。

1.3 类型参数转换

使用“:”设置参数。

protected $casts = ['secret' => Hash::class.':sha256',];

1.4 测试

获取

#App\Controlle\TestController
public function testmodifier() {$r = Article::query()->find(2);$article = $r->article;$istop = $r->is_top;var_dump($istop);$r->article->intro = "test1";$info1 = $r->getAttributes();$info2 = $r->syncAttributes()->getAttributes();$r->intro = "test2";$info3 = $r->getAttributes();var_dump($article, $info1, $info2, $info3);
}
#App1\Model\Article
protected $casts = ['id' => 'integer','created_at' => 'datetime','updated_at' => 'datetime','is_top' => 'boolean','article' => ArticleCasts::class,];
#App1\Attributes\Article 
namespace App1\Attributes;class Article {public $title;public $content;public $intro;public function __construct($title, $intro, $content) {$this->title = $title;$this->content = $content;$this->intro = $intro;}
}
#App1\Casts\ArticleCasts 
namespace App1\Casts;use App1\Attributes\Article;
use Hyperf\Contract\CastsAttributes;class ArticleCasts implements CastsAttributes {/*** 将取出的数据进行转换*/public function get($model, $key, $value, $attributes): Article {return new Article($attributes['title'],$attributes['intro'],$attributes['content']);}/*** 转换成将要进行存储的值*/public function set($model, $key, $value, $attributes) {return ['title' => $value->title,'intro' => $value->intro,'content' => $value->content,];}
}

 测试结果

bool(false)
object(App1\Attributes\Article)#1213 (3) {["title"]=>string(5) "test2"["content"]=>NULL["intro"]=>string(5) "test1"
}
array(10) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-01-13 10:06:06"["deleted_at"]=>NULL["pv_num"]=>int(0)["intro"]=>NULL["content"]=>NULL["is_top"]=>int(0)
}
array(10) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-01-13 10:06:06"["deleted_at"]=>NULL["pv_num"]=>int(0)["intro"]=>string(5) "test1"["content"]=>NULL["is_top"]=>int(0)
}
array(10) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-01-13 10:06:06"["deleted_at"]=>NULL["pv_num"]=>int(0)["intro"]=>string(5) "test2"["content"]=>NULL["is_top"]=>int(0)
}

 写入

#App\Controlle\TestController
public function testmodifier() {$r = Article::query()->find(2);$r->is_top = 1;$r->article->intro = "test2";$attr = $r->getAttributes();var_dump($attr);$r->save();$attr = $r->getAttributes();var_dump($attr);
}

 测试结果

array(10) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-03-25 09:47:00"["deleted_at"]=>NULL["pv_num"]=>int(0)["intro"]=>string(5) "test1"["content"]=>NULL["is_top"]=>int(1)
}
array(10) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(16) "2024-03-25 09:48"["deleted_at"]=>NULL["pv_num"]=>int(0)["intro"]=>string(5) "test2"["content"]=>NULL["is_top"]=>int(1)
}

1.5 源码

转换类型

#Hyperf\Database\Model\Concerns\HasAttributes
public function getAttribute($key){if (!$key) {return;}// If the attribute exists in the attribute array or has a "get" mutator we will// get the attribute's value. Otherwise, we will proceed as if the developers// are asking for a relationship's value. This covers both types of values.if (array_key_exists($key, $this->getAttributes())|| $this->hasGetMutator($key)|| $this->isClassCastable($key)) {return $this->getAttributeValue($key);}// Here we will determine if the model base class itself contains this given key// since we don't want to treat any of those methods as relationships because// they are all intended as helper methods and none of these are relations.if (method_exists(self::class, $key)) {return;}return $this->getRelationValue($key);}
protected function castAttribute($key, $value){$castType = $this->getCastType($key);if (is_null($value) && in_array($castType, static::$primitiveCastTypes)) {return $value;}switch ($castType) {case 'int':case 'integer':return (int) $value;case 'real':case 'float':case 'double':return $this->fromFloat($value);case 'decimal':return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]);case 'string':return (string) $value;case 'bool':case 'boolean':return (bool) $value;case 'object':return $this->fromJson($value, true);case 'array':case 'json':return $this->fromJson($value);case 'collection':return new BaseCollection($this->fromJson($value));case 'date':return $this->asDate($value);case 'datetime':case 'custom_datetime':return $this->asDateTime($value);case 'timestamp':return $this->asTimestamp($value);}if ($this->isClassCastable($key)) {return $this->getClassCastableAttributeValue($key, $value);}return $value;}
protected function asDecimal($value, $decimals){return number_format((float) $value, (int) $decimals, '.', '');}
protected function isDateCastable($key){return $this->hasCast($key, ['date', 'datetime']);}
protected function isJsonCastable($key){return $this->hasCast($key, ['array', 'json', 'object', 'collection']);}
public function getAttributeValue($key){return $this->transformModelValue($key, $this->getAttributeFromArray($key));}
protected function transformModelValue($key, $value){// If the attribute has a get mutator, we will call that then return what// it returns as the value, which is useful for transforming values on// retrieval from the model to a form that is more useful for usage.if ($this->hasGetMutator($key)) {return $this->mutateAttribute($key, $value);}// If the attribute exists within the cast array, we will convert it to// an appropriate native PHP type dependent upon the associated value// given with the key in the pair. Dayle made this comment line up.if ($this->hasCast($key)) {return $this->castAttribute($key, $value);}// If the attribute is listed as a date, we will convert it to a DateTime// instance on retrieval, which makes it quite convenient to work with// date fields without having to create a mutator for each property.if ($value !== null&& \in_array($key, $this->getDates(), false)) {return $this->asDateTime($value);}return $value;}

数据更新

#Hyperf\Database\Model\Concerns\HasAttributes
public function syncAttributes(){$this->mergeAttributesFromClassCasts();return $this;}
protected function mergeAttributesFromClassCasts(){foreach ($this->classCastCache as $key => $value) {if ($value instanceof Synchronized && $value->isSynchronized()) {continue;}$caster = $this->resolveCasterClass($key);$this->attributes = array_merge($this->attributes,$caster instanceof CastsInboundAttributes? [$key => $value]: $this->normalizeCastClassResponse($key, $caster->set($this, $key, $value, $this->attributes)));}}

二 数组和json转换

数据库存json,数据库字段为text或json,数据获取时转变为数组。

获取时使用 Hyperf\Database\Model\Model::__get()调用Hyperf\Database\Model\Concerns\HasAttributes::getAttribute()。

设置时使用Model::__set()调用HasAttributes::setAttribute()。

判断是否可为json数据,则使用json_encode()转化为json数据保存。

根据源码,HasAttributes::casts数组中设置字段类型为array, json, object, collection中的类型,可为json字符串保存。

2.1 测试

#App\Controller\TestController
public function testmodifier() { $article = Article::query()->find(2);$options = $article->content;var_dump($options);if (empty($options)) {$article->content = ['intro' => 'test', 'content' => 'test1'];$article->save();$options = $article->content;}var_dump($options);
}

 测试结果

NULL
array(2) {["intro"]=>string(4) "test"["content"]=>string(5) "test1"
}
select content from articles where id=2{"intro":"test","content":"test1"}

 2.2 源码

getAttribute()源码详见1.5源码。

#Hyperf\Database\Model\Concerns\HasAttributes
public function setAttribute($key, $value) {// First we will check for the presence of a mutator for the set operation// which simply lets the developers tweak the attribute as it is set on// the model, such as "json_encoding" an listing of data for storage.if ($this->hasSetMutator($key)) {return $this->setMutatedAttributeValue($key, $value);}// If an attribute is listed as a "date", we'll convert it from a DateTime// instance into a form proper for storage on the database tables using// the connection grammar's date format. We will auto set the values.if ($value && $this->isDateAttribute($key)) {$value = $this->fromDateTime($value);}if ($this->isClassCastable($key)) {$this->setClassCastableAttribute($key, $value);return $this;}if ($this->isJsonCastable($key) && !is_null($value)) {$value = $this->castAttributeAsJson($key, $value);}// If this attribute contains a JSON ->, we'll set the proper value in the// attribute's underlying array. This takes care of properly nesting an// attribute in the array's value in the case of deeply nested items.if (Str::contains($key, '->')) {return $this->fillJsonAttribute($key, $value);}$this->attributes[$key] = $value;return $this;}
protected function isJsonCastable($key) {return $this->hasCast($key, ['array', 'json', 'object', 'collection']);}
public function hasCast($key, $types = null) {if (array_key_exists($key, $this->getCasts())) {return $types ? in_array($this->getCastType($key), (array) $types, true) : true;}return false;}
public function getCasts() {if ($this->getIncrementing()) {return array_merge([$this->getKeyName() => $this->getKeyType()], $this->casts);}return $this->casts;}
protected function castAttributeAsJson($key, $value) {$value = $this->asJson($value);if ($value === false) {throw JsonEncodingException::forAttribute($this,$key,json_last_error_msg());}return $value;}

三 Date类型转换

在设置的时候,若不是Hyperf\Database\Model\Model::CREATED_AT,Model::UPDATED_AT,即字段不为created_at或updated_at,且设置参数如日期格式,则不会调用转换。

因为判断是否可转换的时候被过滤掉。像官网设置created_at不会被转换,可能和版本有关系。

再说获取。

直接获取对应属性,即运行Hyperf\Database\Model\Model::__get()。 转换类型会被判断为custom_datetime,转换为Carbon类。

但是设置的格式未被解析,还是需要手动设置格式。使用Hyperf\Database\Model\Concerns\HasAttributes::getAttributes()获取,直接获取HasAttributes::attributes属性。

这两种对与设置的格式都不会解析,返回都是根据HasAttributes::dateFormat,其默认值都是Y-m-d H:i:s。

使用HasAttributes::attributesToArray(),会调用HasAttributes::addCastAttributesToArray(),会判断是否为custom_datetime。

是custom_datetime类型,则会调用php系统类自带函数format(),通过解析参数,获得格式化数据。

其实和自己使用format(),运行原理一样,效果也一样。

3.1 测试

#App\Controller\TestController
public function testmodifier() {$pr = PushRecode::query()->find(1);$pr->push_time = date('Y-m-d H:i:s');var_dump($pr->push_time);$pr = $pr->syncAttributes();var_dump($pr->push_time->format('Y-m-d H:00:00'));$pr->created_at = date('Y-m-d H:i:s');$info = $pr->syncAttributes()->getAttributes();var_dump($info);$info = $pr->syncAttributes()->attributesToArray();var_dump($info);
}

测试结果

object(Carbon\Carbon)#1151 (19) {["endOfTime":protected]=>bool(false)["startOfTime":protected]=>bool(false)["constructedObjectId":protected]=>string(32) "00000000607fdc84000000003fa11939"["localMonthsOverflow":protected]=>NULL["localYearsOverflow":protected]=>NULL["localStrictModeEnabled":protected]=>NULL["localHumanDiffOptions":protected]=>NULL["localToStringFormat":protected]=>NULL["localSerializer":protected]=>NULL["localMacros":protected]=>NULL["localGenericMacros":protected]=>NULL["localFormatFunction":protected]=>NULL["localTranslator":protected]=>NULL["dumpProperties":protected]=>array(3) {[0]=>string(4) "date"[1]=>string(13) "timezone_type"[2]=>string(8) "timezone"}["dumpLocale":protected]=>NULL["dumpDateProperties":protected]=>NULL["date"]=>string(26) "2024-04-11 09:30:03.000000"["timezone_type"]=>int(3)["timezone"]=>string(3) "UTC"
}
string(19) "2024-04-11 09:00:00"
array(4) {["id"]=>int(1)["is_push"]=>int(1)["push_time"]=>string(19) "2024-04-11 09:30:03"["created_at"]=>string(19) "2024-04-11 09:30:03"
}
array(4) {["id"]=>int(1)["is_push"]=>int(1)["push_time"]=>string(10) "2024-04-11"["created_at"]=>string(10) "2024-04-11"
}

3.2 源码

Hyperf\Database\Model\Model::getAttribute()内容详见1.5源码。

Hyperf\Database\Model\Model::setAttribute()内容详见2.2源码。

#Hyperf\Database\Model\Concerns\HasAttributes
protected function isClassCastable($key) {return array_key_exists($key, $this->getCasts())&& class_exists($class = $this->parseCasterClass($this->getCasts()[$key]))&& !in_array($class, static::$primitiveCastTypes);}
protected function parseCasterClass($class) {return strpos($class, ':') === false? $class: explode(':', $class, 2)[0];}
protected static $primitiveCastTypes = ['array','bool','boolean','collection','custom_datetime','date','datetime','decimal','double','float','int','integer','json','object','real','string','timestamp',];
public function getCasts() {if ($this->getIncrementing()) {return array_merge([$this->getKeyName() => $this->getKeyType()], $this->casts);}return $this->casts;}public function getAttributes() {return $this->attributes;}protected function isDateAttribute($key) {return in_array($key, $this->getDates(), true)|| $this->isDateCastable($key);}
protected function isDateCastable($key) {return $this->hasCast($key, ['date', 'datetime']);}public function getAttributeValue($key) {return $this->transformModelValue($key, $this->getAttributeFromArray($key));}
protected function transformModelValue($key, $value) {// If the attribute has a get mutator, we will call that then return what// it returns as the value, which is useful for transforming values on// retrieval from the model to a form that is more useful for usage.if ($this->hasGetMutator($key)) {return $this->mutateAttribute($key, $value);}// If the attribute exists within the cast array, we will convert it to// an appropriate native PHP type dependent upon the associated value// given with the key in the pair. Dayle made this comment line up.if ($this->hasCast($key)) {return $this->castAttribute($key, $value);}// If the attribute is listed as a date, we will convert it to a DateTime// instance on retrieval, which makes it quite convenient to work with// date fields without having to create a mutator for each property.if ($value !== null&& \in_array($key, $this->getDates(), false)) {return $this->asDateTime($value);}return $value;}
protected function castAttribute($key, $value) {$castType = $this->getCastType($key);if (is_null($value) && in_array($castType, static::$primitiveCastTypes)) {return $value;}switch ($castType) {case 'int':case 'integer':return (int) $value;case 'real':case 'float':case 'double':return $this->fromFloat($value);case 'decimal':return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]);case 'string':return (string) $value;case 'bool':case 'boolean':return (bool) $value;case 'object':return $this->fromJson($value, true);case 'array':case 'json':return $this->fromJson($value);case 'collection':return new BaseCollection($this->fromJson($value));case 'date':return $this->asDate($value);case 'datetime':case 'custom_datetime':return $this->asDateTime($value);case 'timestamp':return $this->asTimestamp($value);}if ($this->isClassCastable($key)) {return $this->getClassCastableAttributeValue($key, $value);}return $value;}
protected function getCastType($key) {if ($this->isCustomDateTimeCast($this->getCasts()[$key])) {return 'custom_datetime';}if ($this->isDecimalCast($this->getCasts()[$key])) {return 'decimal';}return trim(strtolower($this->getCasts()[$key]));}
protected function asDateTime($value) {// If this value is already a Carbon instance, we shall just return it as is.// This prevents us having to re-instantiate a Carbon instance when we know// it already is one, which wouldn't be fulfilled by the DateTime check.if ($value instanceof Carbon || $value instanceof CarbonInterface) {return Carbon::instance($value);}// If the value is already a DateTime instance, we will just skip the rest of// these checks since they will be a waste of time, and hinder performance// when checking the field. We will just return the DateTime right away.if ($value instanceof DateTimeInterface) {return Carbon::parse($value->format('Y-m-d H:i:s.u'),$value->getTimezone());}// If this value is an integer, we will assume it is a UNIX timestamp's value// and format a Carbon object from this timestamp. This allows flexibility// when defining your date fields as they might be UNIX timestamps here.if (is_numeric($value)) {return Carbon::createFromTimestamp($value);}// If the value is in simply year, month, day format, we will instantiate the// Carbon instances from that format. Again, this provides for simple date// fields on the database, while still supporting Carbonized conversion.if ($this->isStandardDateFormat($value)) {return Carbon::instance(Carbon::createFromFormat('Y-m-d', $value)->startOfDay());}$format = $this->getDateFormat();// Finally, we will just assume this date is in the format used by default on// the database connection and use that format to create the Carbon object// that is returned back out to the developers after we convert it here.if (Carbon::hasFormat($value, $format)) {return Carbon::createFromFormat($format, $value);}return Carbon::parse($value);}
protected function isCustomDateTimeCast($cast) {return strncmp($cast, 'date:', 5) === 0|| strncmp($cast, 'datetime:', 9) === 0;}

根据源码,判断array_key_exists($key, $this->getCasts())、class_exists($class = $this->parseCasterClass($this->getCasts()[$key]))应为true,!in_array($class, static::$primitiveCastTypes)为false,所以isClassCastable()为false。

isDateAttribute()结果应该也为false。

之后执行getAttributeValue(),获取castType为custom_datetime,最终转换为Carbon\Carbon类。

#Hyperf\Database\Model\Concerns\HasAttributes
public function attributesToArray() {// If an attribute is a date, we will cast it to a string after converting it// to a DateTime / Carbon instance. This is so we will get some consistent// formatting while accessing attributes vs. arraying / JSONing a model.$attributes = $this->addDateAttributesToArray($attributes = $this->getArrayableAttributes());$attributes = $this->addMutatedAttributesToArray($attributes,$mutatedAttributes = $this->getMutatedAttributes());// Next we will handle any casts that have been setup for this model and cast// the values to their appropriate type. If the attribute has a mutator we// will not perform the cast on those attributes to avoid any confusion.$attributes = $this->addCastAttributesToArray($attributes,$mutatedAttributes);// Here we will grab all of the appended, calculated attributes to this model// as these attributes are not really in the attributes array, but are run// when we need to array or JSON the model for convenience to the coder.foreach ($this->getArrayableAppends() as $key) {$attributes[$key] = $this->mutateAttributeForArray($key, null);}return $attributes;}
protected function addCastAttributesToArray(array $attributes, array $mutatedAttributes) {foreach ($this->getCasts() as $key => $value) {if (!array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) {continue;}// Here we will cast the attribute. Then, if the cast is a date or datetime cast// then we will serialize the date for the array. This will convert the dates// to strings based on the date format specified for these Model models.$attributes[$key] = $this->castAttribute($key,$attributes[$key]);// If the attribute cast was a date or a datetime, we will serialize the date as// a string. This allows the developers to customize how dates are serialized// into an array without affecting how they are persisted into the storage.if ($attributes[$key]&& ($value === 'date' || $value === 'datetime')) {$attributes[$key] = $this->serializeDate($attributes[$key]);}if ($attributes[$key] && $this->isCustomDateTimeCast($value)) {$attributes[$key] = $attributes[$key]->format(explode(':', $value, 2)[1]);}if ($attributes[$key] instanceof Arrayable) {$attributes[$key] = $attributes[$key]->toArray();}}return $attributes;}

官网打不开了……后续内容等官网好了再说吧……

这篇关于hyperf 二十九 修改器 二的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898017

相关文章

MongoDB学习—(5)修改器$inc,$unset,$push,$pushAll,$allToSet,$pop,$pull,$pullAll

通过db.help()可以查询到关于数据库的操作,一查询发现有很多方法 其中有一个方法为db.getCollection(cname),即通过这一个函数,传入数据库中的一个集合的名称来获取到该集合的一个对象,我们可以编写函数   function insertTenRecord(obj){ var i=0; while(i++<10){ obj.insert({id:i+1,a

《黑神话:悟空》专题合集MOD/修改器/壁纸/音乐/CG剧情

《黑神话:悟空》专题合集」 链接:https://pan.quark.cn/s/d67857f4e308 包含内容: 《黑神话:悟空》MOD合集 《黑神话:悟空》修改器(风灵月影) 《黑神话:悟空》壁纸合集 《黑神话:悟空》3小时CG完整剧情合集 4K120帧最高画质!国语 简中字幕 附:4K 结尾动画合集 ​​​国语 简中字幕 《黑神话:悟空》主题曲 《黑神话

(二十九)STL map容器(映射)与STL pair容器(值对)

C++中的map容器是什么?可以说这个是python中的字典(dict) T = {'1':5, '3':7, '5':4, '4':9, '2':6} print(T) 学过python的都知道字典的每一项都有一个键(key)和一个值(value),而且键是不能重复的 在C++还有一个特点:可以自排序 那值对pair又是个什么东西呢?一个pair可以存储两个数据,这是他的定义: te

leetcode解题思路分析(二十九)207—213题

课程表 你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。 在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1] 给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习? 本题可以采取DFS,如果找到了环路则证明不可以,否则可以 const int maxn=1000050

【Unity 3D】学习笔记二十九:游戏实例——简单小地图制作

任何的学习,光看不练是学不好的。所以这次就总结回顾下怎么制作MMROPG类游戏中的小地图。在MMROPG类游戏里,主角在游戏世界里走动时,一般在屏幕右上角都会有一个区域来显示当前游戏场景的小地图。主角在游戏世界里走动,小地图里代表着主角的小标记也会随之移动。那怎么实现咧? 首先需要确定两个贴图,第一个是右上角的小地图背景贴图,应该是从Y轴俯视向下截取主角所在的位置大地图。第二个就是主角的位置大贴

江湖录-无限内功 百宝箱 修改器 CT 合集

下载地址:https://pan.quark.cn/s/acd6708a083f

C语言基础(二十九)

1、快速排序: #include "date.h"#include <stdio.h> #include <stdlib.h> #include <time.h> // 函数声明 void quickSort(int *arr, int low, int high); void swap(int *xp, int *yp); void printArray(int *ar

黑神话:悟空42项属性修改器中文版风灵月影大神制作

黑神话悟空大家玩上没有? 今天给大家奉上由风灵月影大神制作的修改器,自带简体中文,这下女友再也不会说为什么只有一个怪了。。。 你要问我好不好玩?我得先问问我订的 10 年后的 4090 还有几年能到?是不是到时候就停产了,或者被国产显卡取代了。。。 显卡给力的就支持下正版吧,毕竟这是我国第一款真正的 3A 大作,这种热度,估计不仅前无古人,应该也后无来者了。 立即下载:【chumenx

国产3A大作《黑神话:悟空》,各类MOD+修改器+皮肤等资源大合集(附安装教程)

《黑色神话:悟空》的引擎让你可以修改角色的伤害、防御和各种物资数量,大大降低了游戏的难度,让动作游戏的玩家更容易享受到体验。但是,请注意,使用作弊引擎会大大降低游戏体验,因此请明智地使用它! 游戏今天刚上线就有一大批猴王在第一个妖王BOSS【虎先锋】面前断送了大圣之路,现“风灵月影宗”来带领各位猴王平步青云! 以下是“黑色神话:悟空”的作弊码的完整列表,可以增强你的游戏体

hyperf注解,自定义注解

注解是 Hyperf 非常强大的一项功能,可以通过注解的形式减少很多的配置,以及实现很多非常方便的功能。 结构 建立注解 在app下建立Annotation注解文件夹 在Annotation下建立Jim.php注解 下面的的@Annotation 和 @Target是全局注解,所以不需要use 引入 注解一共有 3 种应用对象,分别是 类、类方法 和 类属性 @Target()