ruby --v找不到_PHP与Ruby-让我们一切相处

ruby --v找不到

Quite often you see developers who have a lot of experience in one language try to play with another, then make a rather quick comparison between the two. This comparison is usually quite worthless, but the clickbait titles get them a lot of traffic.

通常,您会看到在一种语言上有丰富经验的开发人员尝试与另一种语言一起玩,然后在两种语言之间进行了比较快速的比较。 这种比较通常是毫无价值的,但是clickbait标题为他们带来了很多流量。

Instead of doing that, I thought it would be interesting to have a slightly more fair comparison, from the perspective of someone who really enjoys writing both PHP and Ruby, and has done so for years. The aim here is not to find out which is “better”, but to point out a few key things I like about Ruby and its ecosystem.

而不是这样做,我认为从真正喜欢同时编写PHP和Ruby并已经这样做多年的人的角度进行比较公正的比较会很有趣。 这里的目的不是找出哪个“更好”,而是指出我喜欢的关于Ruby及其生态系统的一些关键信息。

Screenshot 2015-11-21 01.20.42

概念差异 (Conceptual differences)

Different languages are often compared to find out which is better, when the differences that make them up are more ideological. Sometimes one thing seems better to one group of people, when that very same thing makes the language a nightmare for other developers.

当构成语言的差异在意识形态上更差时,通常会比较不同的语言以找出哪种更好。 有时候,对于一组人来说,一件事情看起来更好,而当同一件事使该语言成为其他开发人员的噩梦时。

With this in mind, before I get into the “bits of Ruby I like in comparison” I think explaining a few of these conceptual differences will be important.

考虑到这一点,在我进入“我喜欢的Ruby比较”之前,我认为解释其中的一些概念差异很重要。

方法,变量,属性? (Method, Variable, Property?)

PHP offers different syntax to access properties, methods or variables. Ruby does not.

PHP提供了不同的语法来访问属性,方法或变量。 Ruby没有。

PHP

PHP

$this->turtle   # Instance Property
$this->bike()   # Method
$apple          # Variable

Ruby

Ruby

@turtle         # Instance Property
turtle          # "Instance Property" using attr_reader: :turtle
bike            # Method
apple           # Variable

Pedants will point out here that attr_reader :turtle will define a method dynamically, which is used as a getter for @turtle, making turtle and bike the same thing. A PHP developer looking at usage of turtle with no method or variable name explicitly defined will be incredibly confused about where it’s coming from.

步行者将在此处指出attr_reader :turtle将动态定义一个方法,该方法用作@turtle的吸气剂,使turtlebike成为同一事物。 一个PHP开发人员在没有明确定义方法或变量名称的情况下查看turtle用法,将对它的来源感到困惑。

This should not be something that causes you problems too often, but it has caught me out now and then. Sometimes folks on your team might change things from an attr_reader to a full method, or vice-versa, and it might cause knock-on affects.

这不应该是经常引起您麻烦的问题,但是它时不时地吸引我。 有时,您团队中的人可能会将attr_readerattr_reader更改为完整方法,反之亦然,并且可能会引起连锁React。

That said, it can allow for some really flexible APIs, and let you do some cheeky things that you’re thankful for in the heat of the moment.

就是说,它可以允许一些真正灵活的API,并让您做一些厚颜无耻的事情,这些事情在当下的热潮中值得感谢。

Deleted a field, but have loads of code, and a JSON contract still expecting it to be there?

删除了一个字段,但是有大量的代码,并且仍然希望它存在JSON合同?

class Trip
  def canceled_at
    nil
  end
end

That’ll work nicely. Anything calling trip.canceled_at is going to get a nil for this field, which is fine. We’ll remove it properly later.

那会很好。 任何调用trip.canceled_at东西都将为此字段获得nil ,这很好。 我们稍后会正确删除它。

类型提示与鸭子输入 (Type Hints vs. Duck Typing)

In the PHP world, type hints are a weird and wonderful thing. Languages like Golang absolutely require you to define a type for arguments, and return types. PHP added optional type hinting in 5.0 for arguments. You could require arrays, specific class names, interfaces or abstracts, and more recently callables.

在PHP世界中,类型提示是一件奇怪而美妙的事情。 像Golang这样的语言绝对要求您定义参数类型并返回类型。 PHP在5.0中为参数添加了可选的类型提示。 您可能需要数组,特定的类名,接口或抽象,以及最近的可调用项。

PHP 7.0 finally allows return type hinting, along with support for hinting int, string, float, etc. This was done with the scalar type hints RFC. This RFC was bitterly argued and debated, but it got in there, and it is still completely optional; good news for the varied user-base that is PHP.

PHP 7.0最终允许返回类型提示,并支持提示intstringfloat等。这是通过标量类型提示RFC完成的 。 这个RFC经过激烈的争论和辩论,但是它已经存在,并且仍然是完全可选的。 对于各种用户群来说,PHP是个好消息。

Ruby has literally none of that.

Ruby几乎没有。

Duck Typing is the way to go here, which some folks in the PHP world also maintain is a superior approach.

Duck Typing是一种解决方法,PHP世界中的某些人也认为这是一种更好的方法。

Instead of saying: “The argument needs to be an instance of a class which implements FooInterface” and knowing that FooInterface will have a bar(int $a, array $b) method, you essentially say: “The argument can be literally anything that responds to a bar method, and if it doesn’t we can do something else.”

不必说:“该参数必须是实现FooInterface的类的实例”,并且知道FooInterface将具有bar(int $a, array $b)方法,您实际上是说:“该参数实际上可以是任何响应bar方法,如果没有,我们可以做其他事情。”

Ruby

Ruby

def read_data(source)
  return source.read if source.respond_to?(:read)
  return File.read(source.to_str) if source.respond_to?(:to_str)
  raise ArgumentError
end

filename = "foo.txt"
read_data(filename) #=> reads the contents of foo.txt by calling 
                    #   File.read()

input = File.open("foo.txt")
read_data(input) #=> reads the contents of foo.txt via 
                 #   the passed in file handle

This is really flexible, but to some this is a code smell. Especially in a language like PHP where a int(0) or int(1) are considered valid boolean items in weak mode, taking any value and just hoping it works right can be a scary move.

这确实很灵活,但是对于某些人来说这是代码的味道。 尤其是在像PHP这样的语言中,在弱模式下将int(0)int(1)视为有效的布尔项时,采用任何值并只是希望它能正常工作可能是一个可怕的举动。

In the PHP world, we might just define two different methods/functions:

在PHP世界中,我们可能只定义了两种不同的方法/函数:

function read_from_filename(string $filename)
{
    $file = new SplFileObject($filename, "r");
    return read_from_object($file);
}

function read_from_object(SplFileObject $file)
{
  return $file->fread($file->getSize());
}

$filename = "foo.txt";
read_from_filename($filename);

$file = new SplFileObject($filename, "r");
read_from_object($file);

That said, if we wanted to do the exact same duck typing approach in PHP, we easily could:

就是说,如果我们想在PHP中做完全一样的鸭子输入方法,我们可以轻松地做到:

function read_data($source)
{
    if (method_exists($source, 'read')) {
        return $source->read();
    } elseif (is_string($source)) {
        $file = new SplFileObject($source, "r"));
        return $file->fread($file->getSize());
    }
    throw new InvalidArgumentException;
}

$filename = "foo.txt";
read_data($filename); #=> reads the contents of foo.txt by calling 
                      #   SplFileObject->read();

$input = new SplFileObject("foo.txt", "r");
read_data($input); #=> reads the contents of foo.txt via 
                   #   the passed in file handle

You can do either in PHP. PHP doesn’t care.

您可以使用PHP之一。 PHP不在乎。

Pretending that Ruby is “better” because it uses duck typing would be misguided, but very common. You may prefer the approach, and PHP can do both, but basically, Ruby is lacking a feature that PHP has. Being able to do whichever you please does strike me as a bit of a win for PHP, when it is completely impossible to type hint in Ruby even if a developer wanted to.

假装Ruby是“更好的”,因为它使用鸭子类型会被误导,但很常见。 您可能更喜欢这种方法,PHP可以同时使用,但基本上,Ruby缺少PHP具有的功能。 能够做任何您想做的事情对PHP来说都是一个胜利,即使在开发人员愿意的情况下也完全不可能在Ruby中键入提示。

That said, there are many PHP developers who are strongly against type hints, who wished there were none at all and were upset when more were added in PHP 7.0.

就是说,有许多PHP开发人员强烈反对类型提示,他们希望根本没有类型提示,并且在PHP 7.0中添加更多内容时感到不高兴。

Interestingly, Python used to be totally lacking type hints just like Ruby. Then recently they added them. I’d be interested in knowing how many people flipped a table over that transition.

有趣的是,Python曾经像Ruby一样完全缺少类型提示。 然后最近他们添加了它们 。 我想知道有多少人在这一过渡期间翻转了桌子。

有趣的功能 (Fun Features)

Once I’d accepted those differences, I was able to focus on the fun stuff. These are the features I started to notice myself using regularly, or least fairly often.

一旦我接受了这些差异,就可以专注于有趣的东西。 这些是我开始经常或至少经常使用的功能。

嵌套类 (Nested Classes)

Nested classes sound a little alien to PHP developers. Our classes live in namespaces, and a class and a namespace can share the same name. So, if we have a class that is only relevant to one class, we namespace it and that’s it.

嵌套类对PHP开发人员来说有点陌生。 我们的类位于命名空间中,并且一个类和一个命名空间可以共享相同的名称。 因此,如果我们有一个仅与一个类相关的类,则可以为其命名空间。

So, we have a class called Box, which can throw a ExplodingBoxException:

因此,我们有一个名为Box的类,它可以引发ExplodingBoxException

namespace Acme\Foo;

class Box
{
    public function somethingBad()
    {
      throw new Box\ExplodingBoxException;
    }
}

That exception class declaration has to live somewhere. We could put it at the top of the class, but then we have two classes in one file and… well that feels a little funny to many. It also violates PSR-1, which states:

该异常类声明必须存在于某个地方。 我们可以将其放在班级的顶部,但是然后在一个文件中有两个班级,……对许多人来说,这有点可笑。 它还违反了PSR-1,其中规定:

This means each class is in a file by itself, and is in a namespace of at least one level: a top-level vendor name.

这意味着每个类本身都在文件中,并且在至少一个级别的命名空间中:顶级供应商名称。

So, it goes in its own file:

因此,它放在自己的文件中:

namespace Acme\Foo\Box;

class ExplodingBoxException {}

To load that exception we have to hit the autoloader and go to the filesystem again. Doing that isn’t free! PHP 5.6 lowers the overhead for subsequent requests if the opcode cache is enabled, but it is still extra work.

要加载该异常,我们必须点击自动加载器,然后再次进入文件系统。 这样做不是免费的! 如果启用了操作码缓存,PHP 5.6可以降低后续请求的开销,但这仍然是额外的工作。

In Ruby, you can nest a class inside another class:

在Ruby中,您可以将一个类嵌套在另一个类中:

module Acme
  module Foo
    class Box
      class ExplodingBoxError < StandardError; end

      def something_bad!
        raise ExplodingBoxError
      end
    end
  end
end

This is available to the defining class, and available outside of the class too:

这对于定义类是可用的,并且在类之外也可用:

begin
  box = Acme::Foo::Box.new
  box.something_bad!
rescue Acme::Foo::Box::ExplodingBoxError
  # ...
end

That might look a little weird, but it’s pretty cool. A class is only relevant to one class? Group them!

可能看起来有些怪异,但这很酷。 一门课只与一门课有关? 分组!

Another example would be database migrations.

另一个示例是数据库迁移。

Migrations are available in many popular PHP frameworks, from CodeIgniter to Laravel. Anyone who has used them often will know, if you reference a model or any other class in your migrations, then later you change that class, your old migrations will break in weird and wonderful ways.

从CodeIgniter到Laravel,许多流行PHP框架都可以进行迁移。 任何使用过它们的人都会知道,如果您在迁移中引用模型或任何其他类,那么以后再更改该类时,您的旧迁移将以奇怪而奇妙的方式破坏。

Ruby gets around this nicely with nested classes:

Ruby通过嵌套类很好地解决了这个问题:

class PopulateEmployerWithUserAccountName < ActiveRecord::Migration
  class User < ActiveRecord::Base
    belongs_to :account
  end

  class Account < ActiveRecord::Base
    has_many :users
  end

  def up
    Account.find_each do |account|
      account.users.update_all(employer: account.name)
    end
  end

  def down
    # Update all users whose have account id to previous state
    # no employer set
    User.where.not(account_id: nil).update_all(employer: nil)
  end
end

The nested version of the User and Account ORM models will be used instead of the global declared classes, meaning that they are more like snapshots in time of what we need them to be. This is far more useful than calling code with moving goalposts, which could change at any point.

UserAccount ORM模型的嵌套版本代替全局声明的类,这意味着它们在需要时更像快照。 这比用移动的目标杆调用代码要有用得多,后者可以随时更改。

Again, this will sound mad to some people, until you’ve been bitten a few times.

再次,这听起来疯狂的一些人,直到你被咬伤几次。

PHP developers often end up copying complex logic to do this, or write the SQL by hand, which is a waste of time and effort compared to just copying the relevant bits of a model over.

PHP开发人员通常最终会复制复杂的逻辑来执行此操作,或者最终手工编写SQL,与仅复制模型的相关部分相比,这是浪费时间和精力。

调试器 (Debugger)

XDebug is a wonderful piece of work. Don’t get me wrong, using breakpoints is amazing, and revolutionizes the way PHP developers debug their applications, moving beyond the “var_dump() + refresh” debug workflow that is wildly common amongst junior developers.

XDebug是一件很棒的工作。 别误会,使用断点令人惊叹,它改变了PHP开发人员调试应用程序的方式,超越了在初级开发人员中普遍使用的“ var_dump() + refresh”调试工作流。

That said, getting XDebug to work with your IDE of choice, finding the right addon if it’s missing, getting the php.ini tweaked for the right version of PHP to enable zend_extension=xdebug.so for your CLI and web version, getting the breakpoints sent out even if you’re using Vagrant, etc., can be a massive pain in the backside.

就是说,让XDebug与您选择的IDE配合使用,找到合适的插件(如果缺少),对php.ini调整以选择正确PHP版本,以便为您的CLI和Web版本启用zend_extension=xdebug.so ,获取断点。即使您正在使用Vagrant等,将其发送出去也可能会给背面带来巨大的痛苦。

Ruby has a bit of a different approach. Much like debugging JavaScript in the browser, you can just bang the debugger keyword into your code and you’ve got a breakpoint. At the point your code executes that line – be it the $ rails server, a unit test, integration test, etc., you’ll have an instance of a REPL to interact with your code.

Ruby有一些不同的方法。 就像在浏览器中调试JavaScript一样,您只需将debugger关键字插入代码中,就可以得到一个断点。 此时,您的代码将执行该行(例如$ rails server ,单元测试,集成测试等),您将拥有一个REPL实例与您的代码进行交互。

There are a few debuggers around. One popular debugger is called pry, but another is byebug. They’re both gems, installable via Bundler by adding this to your Gemfile:

周围有一些调试器。 一个流行的调试器被称为pry ,但另一个是byebug 。 它们都是宝石,可以通过将其添加到Gemfile来通过Bundler安装:

group :development, :test do
  gem "byebug"
end

This is the equivalent of a dev Composer dependency, and once installed you can just call debugger if you’re using Rails. If not, you’ll need to require "byebug" first.

这等效于dev Composer开发人员的依赖关系,安装后,如果使用Rails,则可以仅调用debugger 。 如果不是,则需要先require "byebug"

A handy Rails guide Debugging Rails Applications, shows how things look if you shove the keyword in your application:

方便的Rails指南调试Rails应用程序 ,显示了在应用程序中推送关键字时的外观:

[1, 10] in /PathTo/project/app/controllers/articles_controller.rb
    3:
    4:   # GET /articles
    5:   # GET /articles.json
    6:   def index
    7:     byebug
=>  8:     @articles = Article.find_recent
    9:
   10:     respond_to do |format|
   11:       format.html # index.html.erb
   12:       format.json { render json: @articles }
 
(byebug)

The arrow shows the line the REPL instance is running in, and you can execute code from right there. At this point, @articles is not yet defined, but you can call Article.find_recent to see what is going on. If it errors, you can either type next to go onto the next line in the same context, or step to go into next instruction to be executed.

箭头显示REPL实例在其中运行的行,您可以从那里开始执行代码。 此时,@ @articles尚未定义,但是您可以调用Article.find_recent来查看发生了什么。 如果出错,则可以键入next在相同上下文中转到下一行,也可以step进入要执行的下一条指令。

Handy stuff, especially when you’re trying to work out why the heck some code is not giving you the output you expect. Inspect every single value until you find the culprit, try and make it work in that context, then whatever ends up being the working code can be copied and pasted into the file.

方便的东西,尤其是当您试图弄清楚为什么有些代码没有给您期望的输出时。 检查每个值,直到找到罪魁祸首,尝试使其在该上下文中起作用,然后可以将最终成为工作代码的任何内容复制并粘贴到文件中。

Doing this in your tests is amazing.

在您的测试中做到这一点是惊人的。

除非 (Unless)

A lot of people do not like unless. It is oft abused, like many features of many programming languages, and unless has been winding people up for years as this article from 2008 points out.

unless很多人不喜欢。 就像许多编程语言的许多功能一样,它经常被滥用, unless像2008年的这篇文章所指出的那样使人们失望多年。

The unless control structure is the opposite of if. Instead of executing the code block when a condition evaluates to true, it will only evaluate when the condition evaluates to false.

unless控制结构与if相反。 当条件评估为true ,它不会执行代码块,而只会在条件评估为false时才执行代码块。

unless foo?
  # bar that thing
end

# Or

def something
  return false unless foo?
  # bar that thing
end

It makes things a bit easier to work out, especially when there are multiple conditions, maybe an || and some parentheses. Instead of switching it with a bang like so: if ! (foo || bar) && baz you can simply do unless (foo || bar) && baz.

它使事情更容易解决,尤其是在有多个条件的情况下,可能|| 和一些括号。 而不是像这样爆炸般切换: if ! (foo || bar) && baz if ! (foo || bar) && baz即可, unless (foo || bar) && baz

Now, this can get a bit much, and nobody at work would let you submit an unless with an else on it, but an unless by itself is a handy feature.

现在,这能有点多,没有人在工作中会让你提交的unlesselse就可以了,而是除非本身是一个很方便的功能。

When people requested this feature for PHP in 2007, it was ignored for a while until PHP creator Rasmus Lerdorf said it would be a BC break to anyone with a unless() function, and it would be “not obvious to non-native English speaking people like myself.”

当人们在2007年为PHP 要求使用此功能时 ,它被忽略了一段时间,直到PHP创建者Rasmus Lerdorf表示,对任何使用unless()函数的人来说,这都是一次BC中断,并且“对于母语不是英语的人来说,这并不明显像我这样的人。”

It is an odd word that essentially means not-if even though it logically should be equivalent to “more” as in the opposite of “more” would be “less” and sticking “un” in front of it suddenly completely changes the meaning entirely.

这是一个奇怪的词,实际上意味着“不是”,即使它在逻辑上应等同于“更多”,因为与“更多”相反的词将是“更少”,而在其前面加“ un”会突然完全改变含义。 。

I disagreed with that, and still do. People reading unless are not going to think it is the “opposite of less” just based on the un. If that were the case, people would read the function uniqid() and think it was the opposite of iqid().

我不同意,但仍然这样做。 unless阅读, unless人们不会仅仅基于un就认为它是“更少的对立面”。 如果真是这样,人们会读函数uniqid()并认为它与iqid()相反。

We suggested as much, and got told that we were “just being silly.” It has since been labeled wontfix.

我们提出了很多建议,并被告知我们“只是愚蠢”。 此后已被标记为wontfix

谓词方法 (Predicate Methods)

There are a few cool conventions in the world of Ruby that PHP is forced to solve in other ways. One of these is predicate methods, which are methods with a boolean response type. Seeing as Ruby has no return type hints, this is a good suggestion of intent to developers using the method.

在Ruby世界中,有一些很酷的约定,PHP被迫以其他方式解决。 其中之一是谓词方法,它们是布尔响应类型的方法。 鉴于Ruby没有返回类型提示,这对于使用该方法的开发人员是一个很好的建议。

Ruby has many built in, such as object.nil?. This is basically $object === nil in PHP. An include? instead of include is also a lot more clear in that it is asking a question, not executing an action.

Ruby内置了许多对象,例如object.nil? 。 在PHP中,这基本上是$object === nil 。 一个include? 而不是include也更加清楚,因为它是在问问题,而不是在执行操作。

Defining your own is pretty cool:

定义自己的方法很酷:

class Rider
  def driver?
    !potential_driver.nil? && vehicle.present?
  end
end

Many PHP developers will do this by prefixing the method name with is and/or has, so instead you have isDriver() and maybe hasVehicle(), but sometimes you have to use other prefixes. A method I wrote in Ruby which was can_drive? would be canDrive() in PHP, and that is not clear it is a predicate method. I’d have to rename it isAbleToDrive() or some guff to make it clear with the is/has tradition rolling in the PHP world.

许多PHP开发人员会通过在方法名称前加上is和/或has ,因此,您拥有isDriver() ,也许还有hasVehicle() ,但是有时您必须使用其他前缀。 我在Ruby中编写的方法can_drive? 在PHP中将为canDrive() ,目前尚不清楚这是一个谓词方法。 我必须将其重命名为isAbleToDrive()或某些名称,以使is / has PHP世界中的传统更加清晰。

更短的数组语法 (Even Shorter Array Syntax)

In PHP, defining literal arrays is easy, and has been made much less verbose in PHP 5.4 with the addition of short array syntax:

在PHP中,定义文字数组很容易,并且在PHP 5.4中增加了简短数组语法,从而使冗长的工作变得不那么繁琐:

// < 5.4
$a = array('one' => 1, 'two' => 2, 'three' => 'three');
// >= 5.4
$a = ['one' => 1, 'two' => 2, 'three' => 'three'];

Some would say that is still a little too verbose. In Ruby 1.9 they added a new option, to allow rockets to be replaced with semi-colons, which if done in PHP would cut this syntax down a little further:

有人会说那仍然太冗长 。 在Ruby 1.9中,他们添加了一个新选项,允许用分号替换火箭,如果用PHP完成,则会将该语法进一步降低:

$a = ['one': 1, 'two': 2, 'three': 'three'];

That is rather nice if you ask me, and when you get to nesting arrays it really saves a bit of typing when you’re doing it a few hundred times in a day.

如果您问我,那很好,当您每天嵌套数百次时,当您嵌套数组时,确实节省了一些键入操作。

Sean Coates suggested this with an RFC back in 2011, but it never made it in.

肖恩·科茨(Sean Coates)早在2011年就通过RFC提出了这一建议,但从未成功。

This may well not make it into PHP ever. PHP tries to be minimalist with its syntax, and is very often against adding new approaches to do old things, even if the new approach is quite a bit nicer. Basically, syntactic sugar is not a priority for PHP maintainers, whereas it seems to be almost a core goal of Ruby.

这可能永远不会使它成为PHP。 PHP试图以其语法最小化,并且即使新方法好得多,也常常反对添加新方法来处理旧事务。 基本上,语法糖并不是PHP维护人员的优先事项,而它似乎几乎是Ruby的核心目标。

对象文字 (Object Literals)

The same RFC linked above highlights a feature in Ruby that I would love to see put into PHP: object literals. In PHP, if you would like to define an StdClass with values, you have two approaches:

上面链接的同一RFC突出显示了Ruby中的一个功能,我希望将其放入PHP:对象文字。 在PHP中,如果您想使用值定义StdClass ,则有两种方法:

$esQuery = new stdClass;
$esQuery->query = new stdClass;
$esQuery->query->term = new stdClass;
$esQuery->query->term->name = 'beer';
$esQuery->size = 1;
 
// OR

$esQuery = (object) array(
   "query" => (object) array(
       "term" => (object) array(
           "name" => "beer"
       )
   ),
   "size" => 1
);

I know this is how it’s been done in PHP forever, but it could be so much easier.

我知道这是永远在PHP中完成的方式,但是它可能要容易得多。

The proposed syntax in the RFC matches Ruby almost exactly:

RFC中提议的语法几乎与Ruby完全匹配:

PHP

PHP

$esQuery = {
   "query" : {
       "term" : {
           "name" : "beer"
       }
   },
   "size" : 1
};

Ruby

Ruby

esQuery = {
   "query" : {
       "term" : {
           "name" : "beer"
       }
   },
   "size" : 1
}

I would really really like this to be done, but again, it has been attempted in the past and met with little interest.

我真的很希望做到这一点,但是再次,过去已经尝试过并且没有兴趣。

救援方法 (Rescue a Method)

Instead of try/catch in PHP, Ruby has begin/rescue. The way they work is essentially identical, with PHP 5.6 even getting finally, to match Ruby’s ensure.

Ruby在PHP中没有begin try / catch ,而是begin / rescue 。 他们的工作方式是基本相同的,与PHP 5.6甚至让finally ,以符合Ruby的ensure

PHP and Ruby can both recover from an exception anywhere, following their respective try or begin keywords, but Ruby can do something really clever: you can skip the begin method, and rescue directly from a function/method body:

PHP和Ruby都可以按照其各自的trybegin关键字在任何地方从异常中恢复,但是Ruby可以做一些非常聪明的事情:您可以跳过begin方法,并直接从函数/方法体中进行救援:

Ruby

Ruby

def create(params)
  do_something_complicated(params)
  true
rescue SomeException
  false
end

If things go wrong, an error can be handled somehow instead of bubbling up and forcing the callee to handle it. Not always what you want, but it’s handy to have the option available, and without needing to indent the whole thing to wrap in a begin.

如果出现问题,可以以某种方式处理错误,而不是冒泡并强迫被调用者处理错误。 并不总是你想要什么,但它的方便有可用的选项,而无需缩进整个事情的包装begin

In PHP this does not work, but the feature could look a little something like this if implemented:

在PHP中这不起作用,但是如果实现,该功能可能看起来像这样:

function create($params) {
  do_something_complicated($params);
  return true;
} catch (SomeException $e) {
  return false;
}

While it might not be wildly important, there are a lot of nice little touches like this that make Ruby feel like it wants to help you.

尽管它可能并不十分重要,但还是有很多类似的小技巧,使Ruby觉得它想为您提供帮助。

异常重试 (Exception Retries)

A few months ago I spotted a really handy feature that I never noticed before, the retry keyword:

几个月前,我发现了一个我从未注意到过的非常方便的功能,即retry关键字:

begin
  SomeModel.find_or_create_by(user: user)
rescue ActiveRecord::RecordNotUnique
  retry
end

In this example, a race condition flares up because the find_or_create_by is not atomic (the ORM does a SELECT and then INSERT) which, if you’re really unlucky, can lead to a record being created by another process after the SELECT but before the INSERT.

在此示例中,由于find_or_create_by不是原子的(ORM先执行SELECT然后INSERT ),所以争用条件加剧了,如果您真倒霉的话,这可能导致记录在SELECT但在SELECT之前由另一个进程创建。 INSERT

As this can only happen once you can simply instruct the begin...rescue to try it again, and it will be found with the SELECT. In other examples, you’d probably want to put some logic in place to only retry once or twice, but let’s just ignore that for a second.

因为只有您可以简单地指示begin...rescue再试一次,这才可能发生,并且可以通过SELECT找到。 在其他示例中,您可能希望放置一些逻辑以仅重试一次或两次,但是让我们忽略它一秒钟。

Focus on how annoying it would be to take one piece of the code and try it again. In Ruby you can do this:

专注于获取一段代码然后重试会多么令人讨厌。 在Ruby中,您可以执行以下操作:

def upload_image
  begin
    obj = s3.bucket('bucket-name').object('key')
    obj.upload_file('/path/to/source/file')
  rescue AWS::S3::UploadException
    retry
  end
end

PHP would require you to create a new function/method just for the contents of the begin block:

PHP将要求您仅针对begin块的内容创建一个新的函数/方法:

function upload_image($path) {
  $attempt = function() use ($path) {
    $obj = $this->s3->bucket('bucket-name')->object('key');
    $obj->upload_file($path);
  };
  
  try {
    $attempt();
  } catch (AWS\S3\UploadException $e)
    $attempt();
  }
}

Again, yes, you’d want to put some boilerplate into both to stop infinite loops, but the Ruby example is certainly much cleaner at retrying the code.

再一次,是的,您想要在两者中都放一些样板来停止无限循环,但是Ruby示例在重试代码时肯定更干净。

A little birdie tells me this feature is actively being developed as an RFC which will hopefully be announced soon. It could theoretically be a PHP 7.1 feature if the process goes well.

一位小鸟告诉我,此功能正在作为RFC积极开发,有望很快发布。 如果过程顺利的话,理论上它可以是PHP 7.1的功能。

最后的想法 (Final Thoughts)

Dabbling with Ruby in the past, I was mostly just writing Ruby like PHP. Working with a team of amazing and extremely experienced Ruby developers for the past year has taught me a lot of Rubyisms and practices that are a little different, and I don’t hate it.

过去涉足Ruby,我主要只是像PHP一样编写Ruby。 在过去的一年中,与一群出色且经验丰富的Ruby开发人员一起工作使我学到了很多与众不同的Rubyism和实践,我并不讨厌。

This article points out things I would miss about Ruby if I went back to working with PHP, but that wouldn’t stop me from doing it. What the PHP haters regularly ignore is the progress being made by the PHP core contributors, and whilst they might not have feature X or Y that I like from Ruby, they have done some amazing things for PHP 7 and PHP 7.1 looks full of interesting surprises.

本文指出了如果我重新使用PHP的话,我会错过有关Ruby的一些知识,但这并不能阻止我这样做。 讨厌PHP的人经常忽略的是PHP核心贡献者正在取得的进步,尽管他们可能没有我喜欢Ruby的X或Y功能,但他们为PHP 7和PHP 7.1做了一些令人惊讶的事情,看起来充满了有趣的惊喜。

PHP has made strong plays towards consistency, with uniform variable syntax, a context-sensitive lexer, and an abstract syntax tree. All of this makes PHP as a whole more consistent, regardless of the inconsistencies in the standard library.

PHP通过统一变量语法上下文相关的词法分析器抽象语法树在一致性方面发挥了重要作用。 所有这些使PHP整体上更加一致,而不管标准库中的不一致之处。

While the standard library isn’t going to be fixed any time soon, if PHP could add a few handy features and sprinklings of syntactic sugar like the ones above, then it would be very nice indeed.

虽然标准库不会在短期内得到修复,但是如果PHP可以添加一些方便的功能以及像上述功能那样的语法糖,那么它的确很好。

Other languages can blaze off in all directions working on new theories, experimenting, making cool stuff that gets the HackerNews types happy, then the stuff that makes sense for PHP to take is eventually grabbed. I like this approach. After all, PHP is a pillaging pirate.

其他语言可以四面八方地研究新理论,进行实验,制作使HackerNews类型感到高兴的很棒的东西,然后最终夺取对PHP有意义的东西。 我喜欢这种方法。 毕竟, PHP是掠夺性海盗

Play with as many languages as you have time and interest in playing with. Ruby is a good start, Golang is a lot of fun and Elixir is quirky but a good challenge, but don’t feel the need to jump ship from one to the other. You can write in a few, and it keeps your brain nice and active.

您可以在有时间和兴趣的情况下使用尽可能多的语言进行游戏。 Ruby是一个很好的开始,Golang很有趣,而Elixir却很古怪,但这是一个很好的挑战,但您并不需要跳船。 您可以编写一些文字,这样可以使您的大脑保持活跃。

翻译自: https://www.sitepoint.com/php-vs-ruby-lets-all-just-get-along/

ruby --v找不到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值