当前位置:   article > 正文

hyperf 二十八 修改器 一

hyperf 二十八 修改器 一

教程:Hyperf

修改器和访问器

根据教程,可设置相关函数,如set属性名Attribute()、get属性名Attribute(),设置和获取属性。这在thinkphp中也常见。

修改器:set属性名Attribute();访问器:get属性名Attribute()。

1.1 原理

模型的父类Hyperf\Database\Model\Model,定义__set()、_get()、__isset()、__unset()函数。

设置属性调用__set(),获取属性调用_get()。

__set()调用set属性名Attribute(),和格式化数据。先通过set属性名Attribute()获取值,再判断是否为日期格式化日期数据。若设置字段类型,会根据设定的字段类型匹配对应的类,返回对应类。会判断是否为json数据返回json格式字符换。若调用的对应字符串含有“->”,则将该对应类对象格式化为json字符串返回。

1.2 测试

  1. #App\Controller\Test
  2. public function testmodifier() {
  3. $result = Article::query()->find(2)->toArray();
  4. var_dump($result);
  5. $article = Article::firstOrCreate(
  6. ['title' => 'test4'],
  7. ['user_id' => 2]
  8. );
  9. $result = Article::query()->where(['title' => '&test4'])->first()->toArray();
  10. var_dump($result);
  11. }
  1. #App1\Model\Article
  2. class Article extends Model implements CacheableInterface {
  3. use Cacheable;
  4. use SoftDeletes;
  5. /**
  6. * The table associated with the model.
  7. *
  8. * @var string
  9. */
  10. protected $table = 'articles';
  11. /**
  12. * The attributes that are mass assignable.
  13. *
  14. * @var array
  15. */
  16. protected $fillable = ['title', 'user_id']; //允许批量赋值
  17. /**
  18. * The attributes that should be cast to native types.
  19. *
  20. * @var array
  21. */
  22. protected $casts = ['id' => 'integer', 'created_at' => 'datetime', 'updated_at' => 'datetime'];
  23. public function setTitleAttribute($value) {
  24. $this->attributes['title'] = "&" . $value;
  25. }
  26. public function getTitleAttribute($value) {
  27. return "标题:" . $value;
  28. }
  29. }

 测试结果

  1. array(7) {
  2. ["id"]=>
  3. int(2)
  4. ["user_id"]=>
  5. int(1)
  6. ["title"]=>
  7. string(14) "标题:test2"
  8. ["created_at"]=>
  9. string(19) "2024-01-13 10:06:04"
  10. ["updated_at"]=>
  11. string(19) "2024-01-13 10:06:06"
  12. ["deleted_at"]=>
  13. NULL
  14. ["pv_num"]=>
  15. int(0)
  16. }
  17. array(7) {
  18. ["id"]=>
  19. int(10)
  20. ["user_id"]=>
  21. int(2)
  22. ["title"]=>
  23. string(15) "标题:&test4"
  24. ["created_at"]=>
  25. string(19) "2024-03-19 08:07:24"
  26. ["updated_at"]=>
  27. string(19) "2024-03-19 08:07:24"
  28. ["deleted_at"]=>
  29. NULL
  30. ["pv_num"]=>
  31. int(0)
  32. }

数据保存使用Hyperf\Database\Model\Builder::firstOrCreate()。firstOrNew()仅在对象中增加数据,未保存进数据库,这是和firstOrCreate()的区别。

过程中创建Hyperf\Database\Model\Model类对象是__construct(),会调用Model::fill()。Model::fill()使用Model::isFillable()调用Model::fillable属性,结果为true,才能设置属性,否则报错。

因为在Article::setTitleAttribute()对传入的属性增加数据。根据测试代码,查询的使用也应该加上“&”。

也是因为使用Builder::firstOrCreate()和Article::setTitleAttribute()修改传入属性,设置查询数据时不会查询到相应数据,因为查询值有差异。

tp中也遇到过相似情况。解决方法,对查询条件中数据也进行数据的换装,保证修改方式和保存之前的数据方式一样。

1.3 源码

  1. #App1\Model\Article
  2. use Hyperf\DbConnection\Model\Model;
  3. class Article extends Model implements CacheableInterface {
  4. use Cacheable;
  5. use SoftDeletes;
  6. }
  7. #Hyperf\DbConnection\Model\Model
  8. use Hyperf\Database\Model\Model as BaseModel;
  9. class Model extends BaseModel
  10. {
  11. use HasContainer;
  12. use HasRepository;
  13. }
  1. #Hyperf\Database\Model\Model
  2. abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable,
  3. CompressInterface {
  4. use Concerns\HasAttributes;
  5. use Concerns\HasEvents;
  6. use Concerns\HasGlobalScopes;
  7. use Concerns\HasRelationships;
  8. use Concerns\HasTimestamps;
  9. use Concerns\HidesAttributes;
  10. use Concerns\GuardsAttributes;
  11. /**
  12. * Dynamically retrieve attributes on the model.
  13. *
  14. * @param string $key
  15. */
  16. public function __get($key) {
  17. return $this->getAttribute($key);
  18. }
  19. /**
  20. * Dynamically set attributes on the model.
  21. *
  22. * @param string $key
  23. * @param mixed $value
  24. */
  25. public function __set($key, $value) {
  26. $this->setAttribute($key, $value);
  27. }
  28. /**
  29. * Determine if an attribute or relation exists on the model.
  30. *
  31. * @param string $key
  32. * @return bool
  33. */
  34. public function __isset($key) {
  35. return $this->offsetExists($key);
  36. }
  37. /**
  38. * Unset an attribute on the model.
  39. *
  40. * @param string $key
  41. */
  42. public function __unset($key) {
  43. $this->offsetUnset($key);
  44. }
  45. }
  1. # Hyperf\Database\Model\Concerns\HasAttributes
  2. /**
  3. * Set a given attribute on the model.
  4. *
  5. * @param string $key
  6. * @param mixed $value
  7. */
  8. public function setAttribute($key, $value)
  9. {
  10. // First we will check for the presence of a mutator for the set operation
  11. // which simply lets the developers tweak the attribute as it is set on
  12. // the model, such as "json_encoding" an listing of data for storage.
  13. if ($this->hasSetMutator($key)) {
  14. return $this->setMutatedAttributeValue($key, $value);
  15. }
  16. // If an attribute is listed as a "date", we'll convert it from a DateTime
  17. // instance into a form proper for storage on the database tables using
  18. // the connection grammar's date format. We will auto set the values.
  19. if ($value && $this->isDateAttribute($key)) {
  20. $value = $this->fromDateTime($value);
  21. }
  22. if ($this->isClassCastable($key)) {
  23. $this->setClassCastableAttribute($key, $value);
  24. return $this;
  25. }
  26. if ($this->isJsonCastable($key) && !is_null($value)) {
  27. $value = $this->castAttributeAsJson($key, $value);
  28. }
  29. // If this attribute contains a JSON ->, we'll set the proper value in the
  30. // attribute's underlying array. This takes care of properly nesting an
  31. // attribute in the array's value in the case of deeply nested items.
  32. if (Str::contains($key, '->')) {
  33. return $this->fillJsonAttribute($key, $value);
  34. }
  35. $this->attributes[$key] = $value;
  36. return $this;
  37. }
  38. /**
  39. * Set the value of an attribute using its mutator.
  40. *
  41. * @param string $key
  42. * @param mixed $value
  43. */
  44. protected function setMutatedAttributeValue($key, $value)
  45. {
  46. return $this->{'set' . Str::studly($key) . 'Attribute'}($value);
  47. }
  48. /**
  49. * Convert a DateTime to a storable string.
  50. *
  51. * @param mixed $value
  52. * @return null|string
  53. */
  54. public function fromDateTime($value)
  55. {
  56. return empty($value) ? $value : $this->asDateTime($value)->format(
  57. $this->getDateFormat()
  58. );
  59. }
  60. /**
  61. * Get the format for database stored dates.
  62. *
  63. * @return string
  64. */
  65. public function getDateFormat()
  66. {
  67. return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();
  68. }
  69. /**
  70. * Set the value of a class castable attribute.
  71. *
  72. * @param string $key
  73. * @param mixed $value
  74. */
  75. protected function setClassCastableAttribute($key, $value)
  76. {
  77. $caster = $this->resolveCasterClass($key);
  78. if (is_null($value)) {
  79. $this->attributes = array_merge($this->attributes, array_map(
  80. function () {
  81. },
  82. $this->normalizeCastClassResponse($key, $caster->set(
  83. $this,
  84. $key,
  85. $this->{$key},
  86. $this->attributes
  87. ))
  88. ));
  89. } else {
  90. $this->attributes = array_merge(
  91. $this->attributes,
  92. $this->normalizeCastClassResponse($key, $caster->set(
  93. $this,
  94. $key,
  95. $value,
  96. $this->attributes
  97. ))
  98. );
  99. }
  100. if ($caster instanceof CastsInboundAttributes || !is_object($value)) {
  101. unset($this->classCastCache[$key]);
  102. } else {
  103. $this->classCastCache[$key] = $value;
  104. }
  105. }
  106. /**
  107. * Cast the given attribute to JSON.
  108. *
  109. * @param string $key
  110. * @param mixed $value
  111. * @return string
  112. */
  113. protected function castAttributeAsJson($key, $value)
  114. {
  115. $value = $this->asJson($value);
  116. if ($value === false) {
  117. throw JsonEncodingException::forAttribute(
  118. $this,
  119. $key,
  120. json_last_error_msg()
  121. );
  122. }
  123. return $value;
  124. }
  125. /**
  126. * Set a given JSON attribute on the model.
  127. *
  128. * @param string $key
  129. * @param mixed $value
  130. * @return $this
  131. */
  132. public function fillJsonAttribute($key, $value)
  133. {
  134. [$key, $path] = explode('->', $key, 2);
  135. $this->attributes[$key] = $this->asJson($this->getArrayAttributeWithValue(
  136. $path,
  137. $key,
  138. $value
  139. ));
  140. return $this;
  141. }

二 日期转化及时间格式化

模型会将 created_atupdated_at 字段转换为 Carbon\Carbon 实例,它继承了 PHP 原生的 DateTime 类并提供了各种有用的方法。可以通过设置模型的 $dates 属性来添加其他日期属性。

2.1 原理

调用Model::_get()、Model::_set()时,会判断字段类型,为日期则转换为Carbon\Carbon类对象。可以设置日期格式。

$date为日期类型字段,$dateFormat为日期格式字符串,都在Hyperf\Database\Model\Concerns\HasAttributes中设置,也是由其转换数据类型。

HasAttributes::castAttribute()处理各种字段类型,HasAttributes::asDate()执行日期类型转换,HasAttributes::getDateFormat()获取日期格式。

日期类型默认包括created_at 、updated_at。日期默认格式"Y-m-d H:i:s"。

2.2 测试

  1. #App1\Model\Article
  2. protected $dateFormat = 'Y-m-d H:i';
  3. public function setTitleAttribute($value) {
  4. $this->attributes['title'] = $value;
  5. }
  6. public function getTitleAttribute($value) {
  7. return $value;
  8. }
  1. #App\Controller\TestController
  2. public function testmodifier() {
  3. $article = Article::firstOrCreate(
  4. ['title' => 'test4'],
  5. ['user_id' => 2]
  6. );
  7. var_dump($article->toArray());
  8. }

 测试结果

  1. array(7) {
  2. ["id"]=>
  3. int(11)
  4. ["user_id"]=>
  5. int(2)
  6. ["title"]=>
  7. string(5) "test4"
  8. ["created_at"]=>
  9. string(16) "2024-03-22 09:04"
  10. ["updated_at"]=>
  11. string(16) "2024-03-22 09:04"
  12. ["deleted_at"]=>
  13. NULL
  14. ["pv_num"]=>
  15. int(0)
  16. }

 

测试可见 数据库中时间格式还是h:i:s,仅获取的时候是h:i格式。

Model::CREATED_AT、Model::UPDATED_AT使用Carbon::now()获取时间,并没有使用$dateFormat属性。

2.3 源码

  1. #Hyperf\Database\Model\Model
  2. public function __get($key) {
  3. return $this->getAttribute($key);
  4. }
  5. public function __set($key, $value) {
  6. $this->setAttribute($key, $value);
  7. }
  8. /**
  9. * 新增时使用
  10. *
  11. * @param \Hyperf\Database\Model\Builder $query
  12. * @return bool
  13. */
  14. protected function performInsert(Builder $query) {
  15. if ($event = $this->fireModelEvent('creating')) {
  16. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  17. return false;
  18. }
  19. }
  20. // First we'll need to create a fresh query instance and touch the creation and
  21. // update timestamps on this model, which are maintained by us for developer
  22. // convenience. After, we will just continue saving these model instances.
  23. if ($this->usesTimestamps()) {
  24. $this->updateTimestamps();
  25. }
  26. // If the model has an incrementing key, we can use the "insertGetId" method on
  27. // the query builder, which will give us back the final inserted ID for this
  28. // table from the database. Not all tables have to be incrementing though.
  29. $attributes = $this->getAttributes();
  30. if ($this->getIncrementing()) {
  31. $this->insertAndSetId($query, $attributes);
  32. }
  33. // If the table isn't incrementing we'll simply insert these attributes as they
  34. // are. These attribute arrays must contain an "id" column previously placed
  35. // there by the developer as the manually determined key for these models.
  36. else {
  37. if (empty($attributes)) {
  38. return true;
  39. }
  40. $query->insert($attributes);
  41. }
  42. // We will go ahead and set the exists property to true, so that it is set when
  43. // the created event is fired, just in case the developer tries to update it
  44. // during the event. This will allow them to do so and run an update here.
  45. $this->exists = true;
  46. $this->wasRecentlyCreated = true;
  47. $this->fireModelEvent('created');
  48. return true;
  49. }
  50. /**
  51. * 修改时使用
  52. *
  53. * @param \Hyperf\Database\Model\Builder $query
  54. * @return bool
  55. */
  56. protected function performUpdate(Builder $query) {
  57. // If the updating event returns false, we will cancel the update operation so
  58. // developers can hook Validation systems into their models and cancel this
  59. // operation if the model does not pass validation. Otherwise, we update.
  60. if ($event = $this->fireModelEvent('updating')) {
  61. if ($event instanceof StoppableEventInterface && $event->isPropagationStopped()) {
  62. return false;
  63. }
  64. }
  65. // First we need to create a fresh query instance and touch the creation and
  66. // update timestamp on the model which are maintained by us for developer
  67. // convenience. Then we will just continue saving the model instances.
  68. if ($this->usesTimestamps()) {
  69. $this->updateTimestamps();
  70. }
  71. // Once we have run the update operation, we will fire the "updated" event for
  72. // this model instance. This will allow developers to hook into these after
  73. // models are updated, giving them a chance to do any special processing.
  74. $dirty = $this->getDirty();
  75. if (count($dirty) > 0) {
  76. $this->setKeysForSaveQuery($query)->update($dirty);
  77. $this->syncChanges();
  78. $this->fireModelEvent('updated');
  79. }
  80. return true;
  81. }
  82. public function save(array $options = []): bool {
  83. $this->mergeAttributesFromClassCasts();
  84. $query = $this->newModelQuery();
  85. // If the "saving" event returns false we'll bail out of the save and return
  86. // false, indicating that the save failed. This provides a chance for any
  87. // listeners to cancel save operations if validations fail or whatever.
  88. if ($saving = $this->fireModelEvent('saving')) {
  89. if ($saving instanceof StoppableEventInterface && $saving->isPropagationStopped()) {
  90. return false;
  91. }
  92. }
  93. // If the model already exists in the database we can just update our record
  94. // that is already in this database using the current IDs in this "where"
  95. // clause to only update this model. Otherwise, we'll just insert them.
  96. if ($this->exists) {
  97. $saved = $this->isDirty() ? $this->performUpdate($query) : true;
  98. } else {
  99. // If the model is brand new, we'll insert it into our database and set the
  100. // ID attribute on the model to the value of the newly inserted row's ID
  101. // which is typically an auto-increment value managed by the database.
  102. $saved = $this->performInsert($query);
  103. if (!$this->getConnectionName() && $connection = $query->getConnection()) {
  104. $this->setConnection($connection->getName());
  105. }
  106. }
  107. // If the model is successfully saved, we need to do a few more things once
  108. // that is done. We will call the "saved" method here to run any actions
  109. // we need to happen after a model gets successfully saved right here.
  110. if ($saved) {
  111. $this->finishSave($options);
  112. }
  113. return $saved;
  114. }
  1. #Hyperf\Database\Model\Concerns\HasAttributes
  2. /**
  3. * Set a given attribute on the model.
  4. *
  5. * @param string $key
  6. * @param mixed $value
  7. */
  8. public function setAttribute($key, $value)
  9. {
  10. // First we will check for the presence of a mutator for the set operation
  11. // which simply lets the developers tweak the attribute as it is set on
  12. // the model, such as "json_encoding" an listing of data for storage.
  13. if ($this->hasSetMutator($key)) {
  14. return $this->setMutatedAttributeValue($key, $value);
  15. }
  16. // If an attribute is listed as a "date", we'll convert it from a DateTime
  17. // instance into a form proper for storage on the database tables using
  18. // the connection grammar's date format. We will auto set the values.
  19. if ($value && $this->isDateAttribute($key)) {
  20. $value = $this->fromDateTime($value);
  21. }
  22. if ($this->isClassCastable($key)) {
  23. $this->setClassCastableAttribute($key, $value);
  24. return $this;
  25. }
  26. if ($this->isJsonCastable($key) && !is_null($value)) {
  27. $value = $this->castAttributeAsJson($key, $value);
  28. }
  29. // If this attribute contains a JSON ->, we'll set the proper value in the
  30. // attribute's underlying array. This takes care of properly nesting an
  31. // attribute in the array's value in the case of deeply nested items.
  32. if (Str::contains($key, '->')) {
  33. return $this->fillJsonAttribute($key, $value);
  34. }
  35. $this->attributes[$key] = $value;
  36. return $this;
  37. }
  38. public function fromDateTime($value)
  39. {
  40. return empty($value) ? $value : $this->asDateTime($value)->format(
  41. $this->getDateFormat()
  42. );
  43. }
  44. /**
  45. * Get an attribute from the model.
  46. *
  47. * @param string $key
  48. */
  49. public function getAttribute($key)
  50. {
  51. if (!$key) {
  52. return;
  53. }
  54. // If the attribute exists in the attribute array or has a "get" mutator we will
  55. // get the attribute's value. Otherwise, we will proceed as if the developers
  56. // are asking for a relationship's value. This covers both types of values.
  57. if (array_key_exists($key, $this->getAttributes())
  58. || $this->hasGetMutator($key)
  59. || $this->isClassCastable($key)) {
  60. return $this->getAttributeValue($key);
  61. }
  62. // Here we will determine if the model base class itself contains this given key
  63. // since we don't want to treat any of those methods as relationships because
  64. // they are all intended as helper methods and none of these are relations.
  65. if (method_exists(self::class, $key)) {
  66. return;
  67. }
  68. return $this->getRelationValue($key);
  69. }
  70. public function getAttributeValue($key)
  71. {
  72. return $this->transformModelValue($key, $this->getAttributeFromArray($key));
  73. }
  74. protected function transformModelValue($key, $value)
  75. {
  76. // If the attribute has a get mutator, we will call that then return what
  77. // it returns as the value, which is useful for transforming values on
  78. // retrieval from the model to a form that is more useful for usage.
  79. if ($this->hasGetMutator($key)) {
  80. return $this->mutateAttribute($key, $value);
  81. }
  82. // If the attribute exists within the cast array, we will convert it to
  83. // an appropriate native PHP type dependent upon the associated value
  84. // given with the key in the pair. Dayle made this comment line up.
  85. if ($this->hasCast($key)) {
  86. return $this->castAttribute($key, $value);
  87. }
  88. // If the attribute is listed as a date, we will convert it to a DateTime
  89. // instance on retrieval, which makes it quite convenient to work with
  90. // date fields without having to create a mutator for each property.
  91. if ($value !== null
  92. && \in_array($key, $this->getDates(), false)) {
  93. return $this->asDateTime($value);
  94. }
  95. return $value;
  96. }
  97. protected function castAttribute($key, $value)
  98. {
  99. $castType = $this->getCastType($key);
  100. if (is_null($value) && in_array($castType, static::$primitiveCastTypes)) {
  101. return $value;
  102. }
  103. switch ($castType) {
  104. case 'int':
  105. case 'integer':
  106. return (int) $value;
  107. case 'real':
  108. case 'float':
  109. case 'double':
  110. return $this->fromFloat($value);
  111. case 'decimal':
  112. return $this->asDecimal($value, explode(':', $this->getCasts()[$key], 2)[1]);
  113. case 'string':
  114. return (string) $value;
  115. case 'bool':
  116. case 'boolean':
  117. return (bool) $value;
  118. case 'object':
  119. return $this->fromJson($value, true);
  120. case 'array':
  121. case 'json':
  122. return $this->fromJson($value);
  123. case 'collection':
  124. return new BaseCollection($this->fromJson($value));
  125. case 'date':
  126. return $this->asDate($value);
  127. case 'datetime':
  128. case 'custom_datetime':
  129. return $this->asDateTime($value);
  130. case 'timestamp':
  131. return $this->asTimestamp($value);
  132. }
  133. if ($this->isClassCastable($key)) {
  134. return $this->getClassCastableAttributeValue($key, $value);
  135. }
  136. return $value;
  137. }
  138. protected function asDate($value)
  139. {
  140. return $this->asDateTime($value)->startOfDay();
  141. }
  142. protected function asDateTime($value)
  143. {
  144. // If this value is already a Carbon instance, we shall just return it as is.
  145. // This prevents us having to re-instantiate a Carbon instance when we know
  146. // it already is one, which wouldn't be fulfilled by the DateTime check.
  147. if ($value instanceof Carbon || $value instanceof CarbonInterface) {
  148. return Carbon::instance($value);
  149. }
  150. // If the value is already a DateTime instance, we will just skip the rest of
  151. // these checks since they will be a waste of time, and hinder performance
  152. // when checking the field. We will just return the DateTime right away.
  153. if ($value instanceof DateTimeInterface) {
  154. return Carbon::parse(
  155. $value->format('Y-m-d H:i:s.u'),
  156. $value->getTimezone()
  157. );
  158. }
  159. // If this value is an integer, we will assume it is a UNIX timestamp's value
  160. // and format a Carbon object from this timestamp. This allows flexibility
  161. // when defining your date fields as they might be UNIX timestamps here.
  162. if (is_numeric($value)) {
  163. return Carbon::createFromTimestamp($value);
  164. }
  165. // If the value is in simply year, month, day format, we will instantiate the
  166. // Carbon instances from that format. Again, this provides for simple date
  167. // fields on the database, while still supporting Carbonized conversion.
  168. if ($this->isStandardDateFormat($value)) {
  169. return Carbon::instance(Carbon::createFromFormat('Y-m-d', $value)->startOfDay());
  170. }
  171. $format = $this->getDateFormat();
  172. // Finally, we will just assume this date is in the format used by default on
  173. // the database connection and use that format to create the Carbon object
  174. // that is returned back out to the developers after we convert it here.
  175. if (Carbon::hasFormat($value, $format)) {
  176. return Carbon::createFromFormat($format, $value);
  177. }
  178. return Carbon::parse($value);
  179. }
  180. public function getDateFormat()
  181. {
  182. return $this->dateFormat ?: $this->getConnection()->getQueryGrammar()->getDateFormat();
  183. }
  1. #Hyperf\Database\Grammar
  2. public function getDateFormat()
  3. {
  4. return 'Y-m-d H:i:s';
  5. }
  1. #Hyperf\Database\Model\Concerns\HasTimestamps
  2. protected function updateTimestamps()
  3. {
  4. $time = $this->freshTimestamp();
  5. if (! is_null(static::UPDATED_AT) && ! $this->isDirty(static::UPDATED_AT)) {
  6. $this->setUpdatedAt($time);
  7. }
  8. if (! $this->exists && ! is_null(static::CREATED_AT)
  9. && ! $this->isDirty(static::CREATED_AT)) {
  10. $this->setCreatedAt($time);
  11. }
  12. }
  13. public function setCreatedAt($value)
  14. {
  15. $this->{static::CREATED_AT} = $value;
  16. return $this;
  17. }
  18. public function setUpdatedAt($value)
  19. {
  20. $this->{static::UPDATED_AT} = $value;
  21. return $this;
  22. }
  23. public function freshTimestamp()
  24. {
  25. return Carbon::now();
  26. }

 

  1. #Carbon\Traits\Creator
  2. public function __construct($time = null, $tz = null)
  3. {
  4. if ($time instanceof DateTimeInterface) {
  5. $time = $this->constructTimezoneFromDateTime($time, $tz)->format('Y-m-d H:i:s.u');
  6. }
  7. if (is_numeric($time) && (!\is_string($time) || !preg_match('/^\d{1,14}$/', $time))) {
  8. $time = static::createFromTimestampUTC($time)->format('Y-m-d\TH:i:s.uP');
  9. }
  10. // If the class has a test now set and we are trying to create a now()
  11. // instance then override as required
  12. $isNow = empty($time) || $time === 'now';
  13. if (method_exists(static::class, 'hasTestNow') &&
  14. method_exists(static::class, 'getTestNow') &&
  15. static::hasTestNow() &&
  16. ($isNow || static::hasRelativeKeywords($time))
  17. ) {
  18. static::mockConstructorParameters($time, $tz);
  19. }
  20. // Work-around for PHP bug https://bugs.php.net/bug.php?id=67127
  21. if (!str_contains((string) .1, '.')) {
  22. $locale = setlocale(LC_NUMERIC, '0'); // @codeCoverageIgnore
  23. setlocale(LC_NUMERIC, 'C'); // @codeCoverageIgnore
  24. }
  25. try {
  26. parent::__construct($time ?: 'now', static::safeCreateDateTimeZone($tz) ?: null);
  27. } catch (Exception $exception) {
  28. throw new InvalidFormatException($exception->getMessage(), 0, $exception);
  29. }
  30. $this->constructedObjectId = spl_object_hash($this);
  31. if (isset($locale)) {
  32. setlocale(LC_NUMERIC, $locale); // @codeCoverageIgnore
  33. }
  34. self::setLastErrors(parent::getLastErrors());
  35. }
  36. public static function now($tz = null)
  37. {
  38. return new static(null, $tz);
  39. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/295571
推荐阅读
相关标签
  

闽ICP备14008679号